125f16c87SAaron Conole#!/usr/bin/env python3 225f16c87SAaron Conole# SPDX-License-Identifier: GPL-2.0 325f16c87SAaron Conole 425f16c87SAaron Conole# Controls the openvswitch module. Part of the kselftest suite, but 525f16c87SAaron Conole# can be used for some diagnostic purpose as well. 625f16c87SAaron Conole 725f16c87SAaron Conoleimport argparse 825f16c87SAaron Conoleimport errno 9e52b07aaSAaron Conoleimport ipaddress 10e52b07aaSAaron Conoleimport logging 1160ccf62dSAdrian Morenoimport math 129feac87bSAaron Conoleimport multiprocessing 13918423fdSAaron Conoleimport re 14f94ecbc9SAaron Conoleimport socket 159feac87bSAaron Conoleimport struct 1625f16c87SAaron Conoleimport sys 17e52b07aaSAaron Conoleimport time 18918423fdSAaron Conoleimport types 19918423fdSAaron Conoleimport uuid 2025f16c87SAaron Conole 2125f16c87SAaron Conoletry: 2225f16c87SAaron Conole from pyroute2 import NDB 2325f16c87SAaron Conole 24e52b07aaSAaron Conole from pyroute2.netlink import NLA_F_NESTED 2525f16c87SAaron Conole from pyroute2.netlink import NLM_F_ACK 26e52b07aaSAaron Conole from pyroute2.netlink import NLM_F_DUMP 2725f16c87SAaron Conole from pyroute2.netlink import NLM_F_REQUEST 2825f16c87SAaron Conole from pyroute2.netlink import genlmsg 2925f16c87SAaron Conole from pyroute2.netlink import nla 30e52b07aaSAaron Conole from pyroute2.netlink import nlmsg_atoms 3130d772a0SAdrian Moreno from pyroute2.netlink.event import EventSocket 3225f16c87SAaron Conole from pyroute2.netlink.exceptions import NetlinkError 3325f16c87SAaron Conole from pyroute2.netlink.generic import GenericNetlinkSocket 3430d772a0SAdrian Moreno from pyroute2.netlink.nlsocket import Marshal 3592e37f20SAaron Conole import pyroute2 36f94ecbc9SAaron Conole import pyroute2.iproute 3792e37f20SAaron Conole 3825f16c87SAaron Conoleexcept ModuleNotFoundError: 3992e37f20SAaron Conole print("Need to install the python pyroute2 package >= 0.6.") 40b7ce46fcSAaron Conole sys.exit(1) 4125f16c87SAaron Conole 4225f16c87SAaron Conole 4325f16c87SAaron ConoleOVS_DATAPATH_FAMILY = "ovs_datapath" 4425f16c87SAaron ConoleOVS_VPORT_FAMILY = "ovs_vport" 4525f16c87SAaron ConoleOVS_FLOW_FAMILY = "ovs_flow" 4625f16c87SAaron ConoleOVS_PACKET_FAMILY = "ovs_packet" 4725f16c87SAaron ConoleOVS_METER_FAMILY = "ovs_meter" 4825f16c87SAaron ConoleOVS_CT_LIMIT_FAMILY = "ovs_ct_limit" 4925f16c87SAaron Conole 5025f16c87SAaron ConoleOVS_DATAPATH_VERSION = 2 5125f16c87SAaron ConoleOVS_DP_CMD_NEW = 1 5225f16c87SAaron ConoleOVS_DP_CMD_DEL = 2 5325f16c87SAaron ConoleOVS_DP_CMD_GET = 3 5425f16c87SAaron ConoleOVS_DP_CMD_SET = 4 5525f16c87SAaron Conole 5625f16c87SAaron ConoleOVS_VPORT_CMD_NEW = 1 5725f16c87SAaron ConoleOVS_VPORT_CMD_DEL = 2 5825f16c87SAaron ConoleOVS_VPORT_CMD_GET = 3 5925f16c87SAaron ConoleOVS_VPORT_CMD_SET = 4 6025f16c87SAaron Conole 61e52b07aaSAaron ConoleOVS_FLOW_CMD_NEW = 1 62e52b07aaSAaron ConoleOVS_FLOW_CMD_DEL = 2 63e52b07aaSAaron ConoleOVS_FLOW_CMD_GET = 3 64e52b07aaSAaron ConoleOVS_FLOW_CMD_SET = 4 65e52b07aaSAaron Conole 6660ccf62dSAdrian MorenoUINT32_MAX = 0xFFFFFFFF 67e52b07aaSAaron Conole 68e52b07aaSAaron Conoledef macstr(mac): 69e52b07aaSAaron Conole outstr = ":".join(["%02X" % i for i in mac]) 70e52b07aaSAaron Conole return outstr 71e52b07aaSAaron Conole 72e52b07aaSAaron Conole 732893ba9cSAaron Conoledef strcspn(str1, str2): 742893ba9cSAaron Conole tot = 0 752893ba9cSAaron Conole for char in str1: 762893ba9cSAaron Conole if str2.find(char) != -1: 772893ba9cSAaron Conole return tot 782893ba9cSAaron Conole tot += 1 792893ba9cSAaron Conole return tot 802893ba9cSAaron Conole 812893ba9cSAaron Conole 82918423fdSAaron Conoledef strspn(str1, str2): 83918423fdSAaron Conole tot = 0 84918423fdSAaron Conole for char in str1: 85918423fdSAaron Conole if str2.find(char) == -1: 86918423fdSAaron Conole return tot 87918423fdSAaron Conole tot += 1 88918423fdSAaron Conole return tot 89918423fdSAaron Conole 90918423fdSAaron Conole 91918423fdSAaron Conoledef intparse(statestr, defmask="0xffffffff"): 92918423fdSAaron Conole totalparse = strspn(statestr, "0123456789abcdefABCDEFx/") 93918423fdSAaron Conole # scan until "/" 94918423fdSAaron Conole count = strspn(statestr, "x0123456789abcdefABCDEF") 95918423fdSAaron Conole 96918423fdSAaron Conole firstnum = statestr[:count] 97918423fdSAaron Conole if firstnum[-1] == "/": 98918423fdSAaron Conole firstnum = firstnum[:-1] 99918423fdSAaron Conole k = int(firstnum, 0) 100918423fdSAaron Conole 101918423fdSAaron Conole m = None 102918423fdSAaron Conole if defmask is not None: 103918423fdSAaron Conole secondnum = defmask 104918423fdSAaron Conole if statestr[count] == "/": 105918423fdSAaron Conole secondnum = statestr[count + 1 :] # this is wrong... 106918423fdSAaron Conole m = int(secondnum, 0) 107918423fdSAaron Conole 108918423fdSAaron Conole return statestr[totalparse + 1 :], k, m 109918423fdSAaron Conole 110918423fdSAaron Conole 111918423fdSAaron Conoledef parse_flags(flag_str, flag_vals): 112918423fdSAaron Conole bitResult = 0 113918423fdSAaron Conole maskResult = 0 114918423fdSAaron Conole 115918423fdSAaron Conole if len(flag_str) == 0: 116918423fdSAaron Conole return flag_str, bitResult, maskResult 117918423fdSAaron Conole 118918423fdSAaron Conole if flag_str[0].isdigit(): 119918423fdSAaron Conole idx = 0 120918423fdSAaron Conole while flag_str[idx].isdigit() or flag_str[idx] == "x": 121918423fdSAaron Conole idx += 1 122918423fdSAaron Conole digits = flag_str[:idx] 123918423fdSAaron Conole flag_str = flag_str[idx:] 124918423fdSAaron Conole 125918423fdSAaron Conole bitResult = int(digits, 0) 126918423fdSAaron Conole maskResult = int(digits, 0) 127918423fdSAaron Conole 128918423fdSAaron Conole while len(flag_str) > 0 and (flag_str[0] == "+" or flag_str[0] == "-"): 129918423fdSAaron Conole if flag_str[0] == "+": 130918423fdSAaron Conole setFlag = True 131918423fdSAaron Conole elif flag_str[0] == "-": 132918423fdSAaron Conole setFlag = False 133918423fdSAaron Conole 134918423fdSAaron Conole flag_str = flag_str[1:] 135918423fdSAaron Conole 136918423fdSAaron Conole flag_len = 0 137918423fdSAaron Conole while ( 138918423fdSAaron Conole flag_str[flag_len] != "+" 139918423fdSAaron Conole and flag_str[flag_len] != "-" 140918423fdSAaron Conole and flag_str[flag_len] != "," 141918423fdSAaron Conole and flag_str[flag_len] != ")" 142918423fdSAaron Conole ): 143918423fdSAaron Conole flag_len += 1 144918423fdSAaron Conole 145918423fdSAaron Conole flag = flag_str[0:flag_len] 146918423fdSAaron Conole 147918423fdSAaron Conole if flag in flag_vals: 148918423fdSAaron Conole if maskResult & flag_vals[flag]: 149918423fdSAaron Conole raise KeyError( 150918423fdSAaron Conole "Flag %s set once, cannot be set in multiples" % flag 151918423fdSAaron Conole ) 152918423fdSAaron Conole 153918423fdSAaron Conole if setFlag: 154918423fdSAaron Conole bitResult |= flag_vals[flag] 155918423fdSAaron Conole 156918423fdSAaron Conole maskResult |= flag_vals[flag] 157918423fdSAaron Conole else: 158918423fdSAaron Conole raise KeyError("Missing flag value: %s" % flag) 159918423fdSAaron Conole 160918423fdSAaron Conole flag_str = flag_str[flag_len:] 161918423fdSAaron Conole 162918423fdSAaron Conole return flag_str, bitResult, maskResult 163918423fdSAaron Conole 164918423fdSAaron Conole 165918423fdSAaron Conoledef parse_ct_state(statestr): 166918423fdSAaron Conole ct_flags = { 167918423fdSAaron Conole "new": 1 << 0, 168918423fdSAaron Conole "est": 1 << 1, 169918423fdSAaron Conole "rel": 1 << 2, 170918423fdSAaron Conole "rpl": 1 << 3, 171918423fdSAaron Conole "inv": 1 << 4, 172918423fdSAaron Conole "trk": 1 << 5, 173918423fdSAaron Conole "snat": 1 << 6, 174918423fdSAaron Conole "dnat": 1 << 7, 175918423fdSAaron Conole } 176918423fdSAaron Conole 177918423fdSAaron Conole return parse_flags(statestr, ct_flags) 178918423fdSAaron Conole 179918423fdSAaron Conole 1809f1179fbSAdrian Morenodef convert_mac(data): 1819f1179fbSAdrian Moreno def to_bytes(mac): 1829f1179fbSAdrian Moreno mac_split = mac.split(":") 183e52b07aaSAaron Conole ret = bytearray([int(i, 16) for i in mac_split]) 184e52b07aaSAaron Conole return bytes(ret) 185e52b07aaSAaron Conole 1869f1179fbSAdrian Moreno mac_str, _, mask_str = data.partition('/') 187e52b07aaSAaron Conole 1889f1179fbSAdrian Moreno if not mac_str: 1899f1179fbSAdrian Moreno mac_str = mask_str = "00:00:00:00:00:00" 1909f1179fbSAdrian Moreno elif not mask_str: 1919f1179fbSAdrian Moreno mask_str = "FF:FF:FF:FF:FF:FF" 192e52b07aaSAaron Conole 1939f1179fbSAdrian Moreno return to_bytes(mac_str), to_bytes(mask_str) 194e52b07aaSAaron Conole 1959f1179fbSAdrian Morenodef convert_ipv4(data): 1969f1179fbSAdrian Moreno ip, _, mask = data.partition('/') 1979f1179fbSAdrian Moreno 1989f1179fbSAdrian Moreno if not ip: 1999f1179fbSAdrian Moreno ip = mask = 0 2009f1179fbSAdrian Moreno elif not mask: 2019f1179fbSAdrian Moreno mask = 0xFFFFFFFF 2029f1179fbSAdrian Moreno elif mask.isdigit(): 2039f1179fbSAdrian Moreno mask = (0xFFFFFFFF << (32 - int(mask))) & 0xFFFFFFFF 2049f1179fbSAdrian Moreno 2059f1179fbSAdrian Moreno return int(ipaddress.IPv4Address(ip)), int(ipaddress.IPv4Address(mask)) 2069f1179fbSAdrian Moreno 20751458e10SAaron Conoledef convert_ipv6(data): 20851458e10SAaron Conole ip, _, mask = data.partition('/') 20951458e10SAaron Conole 21051458e10SAaron Conole if not ip: 21151458e10SAaron Conole ip = mask = 0 21251458e10SAaron Conole elif not mask: 21351458e10SAaron Conole mask = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' 21451458e10SAaron Conole elif mask.isdigit(): 21551458e10SAaron Conole mask = ipaddress.IPv6Network("::/" + mask).hostmask 21651458e10SAaron Conole 21751458e10SAaron Conole return ipaddress.IPv6Address(ip).packed, ipaddress.IPv6Address(mask).packed 21851458e10SAaron Conole 2199f1179fbSAdrian Morenodef convert_int(size): 2209f1179fbSAdrian Moreno def convert_int_sized(data): 2219f1179fbSAdrian Moreno value, _, mask = data.partition('/') 2229f1179fbSAdrian Moreno 2239f1179fbSAdrian Moreno if not value: 2249f1179fbSAdrian Moreno return 0, 0 2259f1179fbSAdrian Moreno elif not mask: 2269f1179fbSAdrian Moreno return int(value, 0), pow(2, size) - 1 2279f1179fbSAdrian Moreno else: 2289f1179fbSAdrian Moreno return int(value, 0), int(mask, 0) 2299f1179fbSAdrian Moreno 2309f1179fbSAdrian Moreno return convert_int_sized 23125f16c87SAaron Conole 232918423fdSAaron Conoledef parse_starts_block(block_str, scanstr, returnskipped, scanregex=False): 233918423fdSAaron Conole if scanregex: 234918423fdSAaron Conole m = re.search(scanstr, block_str) 235918423fdSAaron Conole if m is None: 236918423fdSAaron Conole if returnskipped: 237918423fdSAaron Conole return block_str 238918423fdSAaron Conole return False 239918423fdSAaron Conole if returnskipped: 240918423fdSAaron Conole block_str = block_str[len(m.group(0)) :] 241918423fdSAaron Conole return block_str 242918423fdSAaron Conole return True 243918423fdSAaron Conole 244918423fdSAaron Conole if block_str.startswith(scanstr): 245918423fdSAaron Conole if returnskipped: 246918423fdSAaron Conole block_str = block_str[len(scanstr) :] 247918423fdSAaron Conole else: 248918423fdSAaron Conole return True 249918423fdSAaron Conole 250918423fdSAaron Conole if returnskipped: 251918423fdSAaron Conole return block_str 252918423fdSAaron Conole 253918423fdSAaron Conole return False 254918423fdSAaron Conole 255918423fdSAaron Conole 256918423fdSAaron Conoledef parse_extract_field( 257918423fdSAaron Conole block_str, fieldstr, scanfmt, convert, masked=False, defval=None 258918423fdSAaron Conole): 259918423fdSAaron Conole if fieldstr and not block_str.startswith(fieldstr): 260918423fdSAaron Conole return block_str, defval 261918423fdSAaron Conole 262918423fdSAaron Conole if fieldstr: 263918423fdSAaron Conole str_skiplen = len(fieldstr) 264918423fdSAaron Conole str_skipped = block_str[str_skiplen:] 265918423fdSAaron Conole if str_skiplen == 0: 266918423fdSAaron Conole return str_skipped, defval 267918423fdSAaron Conole else: 268918423fdSAaron Conole str_skiplen = 0 269918423fdSAaron Conole str_skipped = block_str 270918423fdSAaron Conole 271918423fdSAaron Conole m = re.search(scanfmt, str_skipped) 272918423fdSAaron Conole if m is None: 273918423fdSAaron Conole raise ValueError("Bad fmt string") 274918423fdSAaron Conole 275918423fdSAaron Conole data = m.group(0) 276918423fdSAaron Conole if convert: 277918423fdSAaron Conole data = convert(m.group(0)) 278918423fdSAaron Conole 279918423fdSAaron Conole str_skipped = str_skipped[len(m.group(0)) :] 280918423fdSAaron Conole if masked: 281918423fdSAaron Conole if str_skipped[0] == "/": 282918423fdSAaron Conole raise ValueError("Masking support TBD...") 283918423fdSAaron Conole 284918423fdSAaron Conole str_skipped = str_skipped[strspn(str_skipped, ", ") :] 285918423fdSAaron Conole return str_skipped, data 286918423fdSAaron Conole 287918423fdSAaron Conole 28860ccf62dSAdrian Morenodef parse_attrs(actstr, attr_desc): 28960ccf62dSAdrian Moreno """Parses the given action string and returns a list of netlink 29060ccf62dSAdrian Moreno attributes based on a list of attribute descriptions. 29160ccf62dSAdrian Moreno 29260ccf62dSAdrian Moreno Each element in the attribute description list is a tuple such as: 29360ccf62dSAdrian Moreno (name, attr_name, parse_func) 29460ccf62dSAdrian Moreno where: 29560ccf62dSAdrian Moreno name: is the string representing the attribute 29660ccf62dSAdrian Moreno attr_name: is the name of the attribute as defined in the uAPI. 29760ccf62dSAdrian Moreno parse_func: is a callable accepting a string and returning either 29860ccf62dSAdrian Moreno a single object (the parsed attribute value) or a tuple of 29960ccf62dSAdrian Moreno two values (the parsed attribute value and the remaining string) 30060ccf62dSAdrian Moreno 30160ccf62dSAdrian Moreno Returns a list of attributes and the remaining string. 30260ccf62dSAdrian Moreno """ 30360ccf62dSAdrian Moreno def parse_attr(actstr, key, func): 30460ccf62dSAdrian Moreno actstr = actstr[len(key) :] 30560ccf62dSAdrian Moreno 30660ccf62dSAdrian Moreno if not func: 30760ccf62dSAdrian Moreno return None, actstr 30860ccf62dSAdrian Moreno 30960ccf62dSAdrian Moreno delim = actstr[0] 31060ccf62dSAdrian Moreno actstr = actstr[1:] 31160ccf62dSAdrian Moreno 31260ccf62dSAdrian Moreno if delim == "=": 31360ccf62dSAdrian Moreno pos = strcspn(actstr, ",)") 31460ccf62dSAdrian Moreno ret = func(actstr[:pos]) 31560ccf62dSAdrian Moreno else: 31660ccf62dSAdrian Moreno ret = func(actstr) 31760ccf62dSAdrian Moreno 31860ccf62dSAdrian Moreno if isinstance(ret, tuple): 31960ccf62dSAdrian Moreno (datum, actstr) = ret 32060ccf62dSAdrian Moreno else: 32160ccf62dSAdrian Moreno datum = ret 32260ccf62dSAdrian Moreno actstr = actstr[strcspn(actstr, ",)"):] 32360ccf62dSAdrian Moreno 32460ccf62dSAdrian Moreno if delim == "(": 32560ccf62dSAdrian Moreno if not actstr or actstr[0] != ")": 32660ccf62dSAdrian Moreno raise ValueError("Action contains unbalanced parentheses") 32760ccf62dSAdrian Moreno 32860ccf62dSAdrian Moreno actstr = actstr[1:] 32960ccf62dSAdrian Moreno 33060ccf62dSAdrian Moreno actstr = actstr[strspn(actstr, ", ") :] 33160ccf62dSAdrian Moreno 33260ccf62dSAdrian Moreno return datum, actstr 33360ccf62dSAdrian Moreno 33460ccf62dSAdrian Moreno attrs = [] 33560ccf62dSAdrian Moreno attr_desc = list(attr_desc) 33660ccf62dSAdrian Moreno while actstr and actstr[0] != ")" and attr_desc: 33760ccf62dSAdrian Moreno found = False 33860ccf62dSAdrian Moreno for i, (key, attr, func) in enumerate(attr_desc): 33960ccf62dSAdrian Moreno if actstr.startswith(key): 34060ccf62dSAdrian Moreno datum, actstr = parse_attr(actstr, key, func) 34160ccf62dSAdrian Moreno attrs.append([attr, datum]) 34260ccf62dSAdrian Moreno found = True 34360ccf62dSAdrian Moreno del attr_desc[i] 34460ccf62dSAdrian Moreno 34560ccf62dSAdrian Moreno if not found: 34660ccf62dSAdrian Moreno raise ValueError("Unknown attribute: '%s'" % actstr) 34760ccf62dSAdrian Moreno 34860ccf62dSAdrian Moreno actstr = actstr[strspn(actstr, ", ") :] 34960ccf62dSAdrian Moreno 35060ccf62dSAdrian Moreno if actstr[0] != ")": 35160ccf62dSAdrian Moreno raise ValueError("Action string contains extra garbage or has " 35260ccf62dSAdrian Moreno "unbalanced parenthesis: '%s'" % actstr) 35360ccf62dSAdrian Moreno 35460ccf62dSAdrian Moreno return attrs, actstr[1:] 35560ccf62dSAdrian Moreno 35660ccf62dSAdrian Moreno 35725f16c87SAaron Conoleclass ovs_dp_msg(genlmsg): 35825f16c87SAaron Conole # include the OVS version 35925f16c87SAaron Conole # We need a custom header rather than just being able to rely on 36025f16c87SAaron Conole # genlmsg because fields ends up not expressing everything correctly 36125f16c87SAaron Conole # if we use the canonical example of setting fields = (('customfield',),) 36225f16c87SAaron Conole fields = genlmsg.fields + (("dpifindex", "I"),) 36325f16c87SAaron Conole 36425f16c87SAaron Conole 365e52b07aaSAaron Conoleclass ovsactions(nla): 366e52b07aaSAaron Conole nla_flags = NLA_F_NESTED 367e52b07aaSAaron Conole 368e52b07aaSAaron Conole nla_map = ( 369e52b07aaSAaron Conole ("OVS_ACTION_ATTR_UNSPEC", "none"), 370e52b07aaSAaron Conole ("OVS_ACTION_ATTR_OUTPUT", "uint32"), 371e52b07aaSAaron Conole ("OVS_ACTION_ATTR_USERSPACE", "userspace"), 372a4126f90SAaron Conole ("OVS_ACTION_ATTR_SET", "ovskey"), 373e52b07aaSAaron Conole ("OVS_ACTION_ATTR_PUSH_VLAN", "none"), 374e52b07aaSAaron Conole ("OVS_ACTION_ATTR_POP_VLAN", "flag"), 37560ccf62dSAdrian Moreno ("OVS_ACTION_ATTR_SAMPLE", "sample"), 376e52b07aaSAaron Conole ("OVS_ACTION_ATTR_RECIRC", "uint32"), 377e52b07aaSAaron Conole ("OVS_ACTION_ATTR_HASH", "none"), 378e52b07aaSAaron Conole ("OVS_ACTION_ATTR_PUSH_MPLS", "none"), 379e52b07aaSAaron Conole ("OVS_ACTION_ATTR_POP_MPLS", "flag"), 380a4126f90SAaron Conole ("OVS_ACTION_ATTR_SET_MASKED", "ovskey"), 381e52b07aaSAaron Conole ("OVS_ACTION_ATTR_CT", "ctact"), 382e52b07aaSAaron Conole ("OVS_ACTION_ATTR_TRUNC", "uint32"), 383e52b07aaSAaron Conole ("OVS_ACTION_ATTR_PUSH_ETH", "none"), 384e52b07aaSAaron Conole ("OVS_ACTION_ATTR_POP_ETH", "flag"), 385e52b07aaSAaron Conole ("OVS_ACTION_ATTR_CT_CLEAR", "flag"), 386e52b07aaSAaron Conole ("OVS_ACTION_ATTR_PUSH_NSH", "none"), 387e52b07aaSAaron Conole ("OVS_ACTION_ATTR_POP_NSH", "flag"), 388e52b07aaSAaron Conole ("OVS_ACTION_ATTR_METER", "none"), 389bd128f62SAaron Conole ("OVS_ACTION_ATTR_CLONE", "recursive"), 390e52b07aaSAaron Conole ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"), 391e52b07aaSAaron Conole ("OVS_ACTION_ATTR_ADD_MPLS", "none"), 392e52b07aaSAaron Conole ("OVS_ACTION_ATTR_DEC_TTL", "none"), 393e7bc7db9SEric Garver ("OVS_ACTION_ATTR_DROP", "uint32"), 39460ccf62dSAdrian Moreno ("OVS_ACTION_ATTR_PSAMPLE", "psample"), 395e52b07aaSAaron Conole ) 396e52b07aaSAaron Conole 39760ccf62dSAdrian Moreno class psample(nla): 39860ccf62dSAdrian Moreno nla_flags = NLA_F_NESTED 39960ccf62dSAdrian Moreno 40060ccf62dSAdrian Moreno nla_map = ( 40160ccf62dSAdrian Moreno ("OVS_PSAMPLE_ATTR_UNSPEC", "none"), 40260ccf62dSAdrian Moreno ("OVS_PSAMPLE_ATTR_GROUP", "uint32"), 40360ccf62dSAdrian Moreno ("OVS_PSAMPLE_ATTR_COOKIE", "array(uint8)"), 40460ccf62dSAdrian Moreno ) 40560ccf62dSAdrian Moreno 40660ccf62dSAdrian Moreno def dpstr(self, more=False): 40760ccf62dSAdrian Moreno args = "group=%d" % self.get_attr("OVS_PSAMPLE_ATTR_GROUP") 40860ccf62dSAdrian Moreno 40960ccf62dSAdrian Moreno cookie = self.get_attr("OVS_PSAMPLE_ATTR_COOKIE") 41060ccf62dSAdrian Moreno if cookie: 41160ccf62dSAdrian Moreno args += ",cookie(%s)" % \ 41260ccf62dSAdrian Moreno "".join(format(x, "02x") for x in cookie) 41360ccf62dSAdrian Moreno 41460ccf62dSAdrian Moreno return "psample(%s)" % args 41560ccf62dSAdrian Moreno 41660ccf62dSAdrian Moreno def parse(self, actstr): 41760ccf62dSAdrian Moreno desc = ( 41860ccf62dSAdrian Moreno ("group", "OVS_PSAMPLE_ATTR_GROUP", int), 41960ccf62dSAdrian Moreno ("cookie", "OVS_PSAMPLE_ATTR_COOKIE", 42060ccf62dSAdrian Moreno lambda x: list(bytearray.fromhex(x))) 42160ccf62dSAdrian Moreno ) 42260ccf62dSAdrian Moreno 42360ccf62dSAdrian Moreno attrs, actstr = parse_attrs(actstr, desc) 42460ccf62dSAdrian Moreno 42560ccf62dSAdrian Moreno for attr in attrs: 42660ccf62dSAdrian Moreno self["attrs"].append(attr) 42760ccf62dSAdrian Moreno 42860ccf62dSAdrian Moreno return actstr 42960ccf62dSAdrian Moreno 43060ccf62dSAdrian Moreno class sample(nla): 43160ccf62dSAdrian Moreno nla_flags = NLA_F_NESTED 43260ccf62dSAdrian Moreno 43360ccf62dSAdrian Moreno nla_map = ( 43460ccf62dSAdrian Moreno ("OVS_SAMPLE_ATTR_UNSPEC", "none"), 43560ccf62dSAdrian Moreno ("OVS_SAMPLE_ATTR_PROBABILITY", "uint32"), 43660ccf62dSAdrian Moreno ("OVS_SAMPLE_ATTR_ACTIONS", "ovsactions"), 43760ccf62dSAdrian Moreno ) 43860ccf62dSAdrian Moreno 43960ccf62dSAdrian Moreno def dpstr(self, more=False): 44060ccf62dSAdrian Moreno args = [] 44160ccf62dSAdrian Moreno 44260ccf62dSAdrian Moreno args.append("sample={:.2f}%".format( 44360ccf62dSAdrian Moreno 100 * self.get_attr("OVS_SAMPLE_ATTR_PROBABILITY") / 44460ccf62dSAdrian Moreno UINT32_MAX)) 44560ccf62dSAdrian Moreno 44660ccf62dSAdrian Moreno actions = self.get_attr("OVS_SAMPLE_ATTR_ACTIONS") 44760ccf62dSAdrian Moreno if actions: 44860ccf62dSAdrian Moreno args.append("actions(%s)" % actions.dpstr(more)) 44960ccf62dSAdrian Moreno 45060ccf62dSAdrian Moreno return "sample(%s)" % ",".join(args) 45160ccf62dSAdrian Moreno 45260ccf62dSAdrian Moreno def parse(self, actstr): 45360ccf62dSAdrian Moreno def parse_nested_actions(actstr): 45460ccf62dSAdrian Moreno subacts = ovsactions() 45560ccf62dSAdrian Moreno parsed_len = subacts.parse(actstr) 45660ccf62dSAdrian Moreno return subacts, actstr[parsed_len :] 45760ccf62dSAdrian Moreno 45860ccf62dSAdrian Moreno def percent_to_rate(percent): 45960ccf62dSAdrian Moreno percent = float(percent.strip('%')) 46060ccf62dSAdrian Moreno return int(math.floor(UINT32_MAX * (percent / 100.0) + .5)) 46160ccf62dSAdrian Moreno 46260ccf62dSAdrian Moreno desc = ( 46360ccf62dSAdrian Moreno ("sample", "OVS_SAMPLE_ATTR_PROBABILITY", percent_to_rate), 46460ccf62dSAdrian Moreno ("actions", "OVS_SAMPLE_ATTR_ACTIONS", parse_nested_actions), 46560ccf62dSAdrian Moreno ) 46660ccf62dSAdrian Moreno attrs, actstr = parse_attrs(actstr, desc) 46760ccf62dSAdrian Moreno 46860ccf62dSAdrian Moreno for attr in attrs: 46960ccf62dSAdrian Moreno self["attrs"].append(attr) 47060ccf62dSAdrian Moreno 47160ccf62dSAdrian Moreno return actstr 47260ccf62dSAdrian Moreno 473e52b07aaSAaron Conole class ctact(nla): 474e52b07aaSAaron Conole nla_flags = NLA_F_NESTED 475e52b07aaSAaron Conole 476e52b07aaSAaron Conole nla_map = ( 477e52b07aaSAaron Conole ("OVS_CT_ATTR_NONE", "none"), 478e52b07aaSAaron Conole ("OVS_CT_ATTR_COMMIT", "flag"), 479e52b07aaSAaron Conole ("OVS_CT_ATTR_ZONE", "uint16"), 480e52b07aaSAaron Conole ("OVS_CT_ATTR_MARK", "none"), 481e52b07aaSAaron Conole ("OVS_CT_ATTR_LABELS", "none"), 482e52b07aaSAaron Conole ("OVS_CT_ATTR_HELPER", "asciiz"), 483e52b07aaSAaron Conole ("OVS_CT_ATTR_NAT", "natattr"), 484e52b07aaSAaron Conole ("OVS_CT_ATTR_FORCE_COMMIT", "flag"), 485e52b07aaSAaron Conole ("OVS_CT_ATTR_EVENTMASK", "uint32"), 486e52b07aaSAaron Conole ("OVS_CT_ATTR_TIMEOUT", "asciiz"), 487e52b07aaSAaron Conole ) 488e52b07aaSAaron Conole 489e52b07aaSAaron Conole class natattr(nla): 490e52b07aaSAaron Conole nla_flags = NLA_F_NESTED 491e52b07aaSAaron Conole 492e52b07aaSAaron Conole nla_map = ( 493e52b07aaSAaron Conole ("OVS_NAT_ATTR_NONE", "none"), 494e52b07aaSAaron Conole ("OVS_NAT_ATTR_SRC", "flag"), 495e52b07aaSAaron Conole ("OVS_NAT_ATTR_DST", "flag"), 496e52b07aaSAaron Conole ("OVS_NAT_ATTR_IP_MIN", "ipaddr"), 497e52b07aaSAaron Conole ("OVS_NAT_ATTR_IP_MAX", "ipaddr"), 498e52b07aaSAaron Conole ("OVS_NAT_ATTR_PROTO_MIN", "uint16"), 499e52b07aaSAaron Conole ("OVS_NAT_ATTR_PROTO_MAX", "uint16"), 500e52b07aaSAaron Conole ("OVS_NAT_ATTR_PERSISTENT", "flag"), 501e52b07aaSAaron Conole ("OVS_NAT_ATTR_PROTO_HASH", "flag"), 502e52b07aaSAaron Conole ("OVS_NAT_ATTR_PROTO_RANDOM", "flag"), 503e52b07aaSAaron Conole ) 504e52b07aaSAaron Conole 505e52b07aaSAaron Conole def dpstr(self, more=False): 506e52b07aaSAaron Conole print_str = "nat(" 507e52b07aaSAaron Conole 508e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_SRC"): 509e52b07aaSAaron Conole print_str += "src" 510e52b07aaSAaron Conole elif self.get_attr("OVS_NAT_ATTR_DST"): 511e52b07aaSAaron Conole print_str += "dst" 512e52b07aaSAaron Conole else: 513e52b07aaSAaron Conole print_str += "XXX-unknown-nat" 514e52b07aaSAaron Conole 515e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr( 516e52b07aaSAaron Conole "OVS_NAT_ATTR_IP_MAX" 517e52b07aaSAaron Conole ): 518e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_IP_MIN"): 519e52b07aaSAaron Conole print_str += "=%s," % str( 520e52b07aaSAaron Conole self.get_attr("OVS_NAT_ATTR_IP_MIN") 521e52b07aaSAaron Conole ) 522e52b07aaSAaron Conole 523e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_IP_MAX"): 524e52b07aaSAaron Conole print_str += "-%s," % str( 525e52b07aaSAaron Conole self.get_attr("OVS_NAT_ATTR_IP_MAX") 526e52b07aaSAaron Conole ) 527e52b07aaSAaron Conole else: 528e52b07aaSAaron Conole print_str += "," 529e52b07aaSAaron Conole 530e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"): 531e52b07aaSAaron Conole print_str += "proto_min=%d," % self.get_attr( 532e52b07aaSAaron Conole "OVS_NAT_ATTR_PROTO_MIN" 533e52b07aaSAaron Conole ) 534e52b07aaSAaron Conole 535e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"): 536e52b07aaSAaron Conole print_str += "proto_max=%d," % self.get_attr( 537e52b07aaSAaron Conole "OVS_NAT_ATTR_PROTO_MAX" 538e52b07aaSAaron Conole ) 539e52b07aaSAaron Conole 540e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_PERSISTENT"): 541e52b07aaSAaron Conole print_str += "persistent," 542e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_HASH"): 543e52b07aaSAaron Conole print_str += "hash," 544e52b07aaSAaron Conole if self.get_attr("OVS_NAT_ATTR_RANDOM"): 545e52b07aaSAaron Conole print_str += "random" 546e52b07aaSAaron Conole print_str += ")" 547e52b07aaSAaron Conole return print_str 548e52b07aaSAaron Conole 549e52b07aaSAaron Conole def dpstr(self, more=False): 550e52b07aaSAaron Conole print_str = "ct(" 551e52b07aaSAaron Conole 552e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_COMMIT") is not None: 553e52b07aaSAaron Conole print_str += "commit," 554e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_ZONE") is not None: 555e52b07aaSAaron Conole print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE") 556e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_HELPER") is not None: 557e52b07aaSAaron Conole print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER") 558e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_NAT") is not None: 559e52b07aaSAaron Conole print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more) 560e52b07aaSAaron Conole print_str += "," 561e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None: 562e52b07aaSAaron Conole print_str += "force," 563e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None: 564e52b07aaSAaron Conole print_str += "emask=0x%X," % self.get_attr( 565e52b07aaSAaron Conole "OVS_CT_ATTR_EVENTMASK" 566e52b07aaSAaron Conole ) 567e52b07aaSAaron Conole if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None: 568e52b07aaSAaron Conole print_str += "timeout=%s" % self.get_attr( 569e52b07aaSAaron Conole "OVS_CT_ATTR_TIMEOUT" 570e52b07aaSAaron Conole ) 571e52b07aaSAaron Conole print_str += ")" 572e52b07aaSAaron Conole return print_str 573e52b07aaSAaron Conole 574e52b07aaSAaron Conole class userspace(nla): 575e52b07aaSAaron Conole nla_flags = NLA_F_NESTED 576e52b07aaSAaron Conole 577e52b07aaSAaron Conole nla_map = ( 578e52b07aaSAaron Conole ("OVS_USERSPACE_ATTR_UNUSED", "none"), 579e52b07aaSAaron Conole ("OVS_USERSPACE_ATTR_PID", "uint32"), 580e52b07aaSAaron Conole ("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"), 581e52b07aaSAaron Conole ("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"), 582e52b07aaSAaron Conole ) 583e52b07aaSAaron Conole 584e52b07aaSAaron Conole def dpstr(self, more=False): 585e52b07aaSAaron Conole print_str = "userspace(" 586e52b07aaSAaron Conole if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None: 587e52b07aaSAaron Conole print_str += "pid=%d," % self.get_attr( 588e52b07aaSAaron Conole "OVS_USERSPACE_ATTR_PID" 589e52b07aaSAaron Conole ) 590e52b07aaSAaron Conole if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None: 591e52b07aaSAaron Conole print_str += "userdata=" 592e52b07aaSAaron Conole for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"): 593e52b07aaSAaron Conole print_str += "%x." % f 594c7815abbSAdrian Moreno if self.get_attr("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT") is not None: 595e52b07aaSAaron Conole print_str += "egress_tun_port=%d" % self.get_attr( 596c7815abbSAdrian Moreno "OVS_USERSPACE_ATTR_EGRESS_TUN_PORT" 597e52b07aaSAaron Conole ) 598e52b07aaSAaron Conole print_str += ")" 599e52b07aaSAaron Conole return print_str 600e52b07aaSAaron Conole 601c7815abbSAdrian Moreno def parse(self, actstr): 602c7815abbSAdrian Moreno attrs_desc = ( 603c7815abbSAdrian Moreno ("pid", "OVS_USERSPACE_ATTR_PID", int), 604c7815abbSAdrian Moreno ("userdata", "OVS_USERSPACE_ATTR_USERDATA", 605c7815abbSAdrian Moreno lambda x: list(bytearray.fromhex(x))), 606c7815abbSAdrian Moreno ("egress_tun_port", "OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", int) 607c7815abbSAdrian Moreno ) 608c7815abbSAdrian Moreno 609c7815abbSAdrian Moreno attrs, actstr = parse_attrs(actstr, attrs_desc) 610c7815abbSAdrian Moreno for attr in attrs: 611c7815abbSAdrian Moreno self["attrs"].append(attr) 612c7815abbSAdrian Moreno 613c7815abbSAdrian Moreno return actstr 614c7815abbSAdrian Moreno 615e52b07aaSAaron Conole def dpstr(self, more=False): 616e52b07aaSAaron Conole print_str = "" 617e52b07aaSAaron Conole 61837de65a7SAaron Conole for field in self["attrs"]: 619e52b07aaSAaron Conole if field[1] == "none" or self.get_attr(field[0]) is None: 620e52b07aaSAaron Conole continue 621e52b07aaSAaron Conole if print_str != "": 622e52b07aaSAaron Conole print_str += "," 623e52b07aaSAaron Conole 624e52b07aaSAaron Conole if field[0] == "OVS_ACTION_ATTR_OUTPUT": 625e52b07aaSAaron Conole print_str += "%d" % int(self.get_attr(field[0])) 626e52b07aaSAaron Conole elif field[0] == "OVS_ACTION_ATTR_RECIRC": 627e52b07aaSAaron Conole print_str += "recirc(0x%x)" % int(self.get_attr(field[0])) 628e52b07aaSAaron Conole elif field[0] == "OVS_ACTION_ATTR_TRUNC": 629e52b07aaSAaron Conole print_str += "trunc(%d)" % int(self.get_attr(field[0])) 630e7bc7db9SEric Garver elif field[0] == "OVS_ACTION_ATTR_DROP": 631e7bc7db9SEric Garver print_str += "drop(%d)" % int(self.get_attr(field[0])) 63237de65a7SAaron Conole elif field[0] == "OVS_ACTION_ATTR_CT_CLEAR": 633e52b07aaSAaron Conole print_str += "ct_clear" 634e52b07aaSAaron Conole elif field[0] == "OVS_ACTION_ATTR_POP_VLAN": 635e52b07aaSAaron Conole print_str += "pop_vlan" 636e52b07aaSAaron Conole elif field[0] == "OVS_ACTION_ATTR_POP_ETH": 637e52b07aaSAaron Conole print_str += "pop_eth" 638e52b07aaSAaron Conole elif field[0] == "OVS_ACTION_ATTR_POP_NSH": 639e52b07aaSAaron Conole print_str += "pop_nsh" 640e52b07aaSAaron Conole elif field[0] == "OVS_ACTION_ATTR_POP_MPLS": 641e52b07aaSAaron Conole print_str += "pop_mpls" 642e52b07aaSAaron Conole else: 643e52b07aaSAaron Conole datum = self.get_attr(field[0]) 644bd128f62SAaron Conole if field[0] == "OVS_ACTION_ATTR_CLONE": 645bd128f62SAaron Conole print_str += "clone(" 646bd128f62SAaron Conole print_str += datum.dpstr(more) 647bd128f62SAaron Conole print_str += ")" 648a4126f90SAaron Conole elif field[0] == "OVS_ACTION_ATTR_SET" or \ 649a4126f90SAaron Conole field[0] == "OVS_ACTION_ATTR_SET_MASKED": 650a4126f90SAaron Conole print_str += "set" 651a4126f90SAaron Conole field = datum 652a4126f90SAaron Conole mask = None 653a4126f90SAaron Conole if field[0] == "OVS_ACTION_ATTR_SET_MASKED": 654a4126f90SAaron Conole print_str += "_masked" 655a4126f90SAaron Conole field = datum[0] 656a4126f90SAaron Conole mask = datum[1] 657a4126f90SAaron Conole print_str += "(" 658a4126f90SAaron Conole print_str += field.dpstr(mask, more) 659a4126f90SAaron Conole print_str += ")" 660bd128f62SAaron Conole else: 66137de65a7SAaron Conole try: 662e52b07aaSAaron Conole print_str += datum.dpstr(more) 66337de65a7SAaron Conole except: 66437de65a7SAaron Conole print_str += "{ATTR: %s not decoded}" % field[0] 665e52b07aaSAaron Conole 666e52b07aaSAaron Conole return print_str 667e52b07aaSAaron Conole 668918423fdSAaron Conole def parse(self, actstr): 669bd128f62SAaron Conole totallen = len(actstr) 670918423fdSAaron Conole while len(actstr) != 0: 671918423fdSAaron Conole parsed = False 672bd128f62SAaron Conole parencount = 0 673918423fdSAaron Conole if actstr.startswith("drop"): 674e7bc7db9SEric Garver # If no reason is provided, the implicit drop is used (i.e no 675e7bc7db9SEric Garver # action). If some reason is given, an explicit action is used. 676bd128f62SAaron Conole reason = None 677bd128f62SAaron Conole if actstr.startswith("drop("): 678bd128f62SAaron Conole parencount += 1 679bd128f62SAaron Conole 680e7bc7db9SEric Garver actstr, reason = parse_extract_field( 681e7bc7db9SEric Garver actstr, 682e7bc7db9SEric Garver "drop(", 6833fde60afSAdrian Moreno r"([0-9]+)", 684e7bc7db9SEric Garver lambda x: int(x, 0), 685e7bc7db9SEric Garver False, 686e7bc7db9SEric Garver None, 687e7bc7db9SEric Garver ) 688bd128f62SAaron Conole 689e7bc7db9SEric Garver if reason is not None: 690e7bc7db9SEric Garver self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason]) 691e7bc7db9SEric Garver parsed = True 692e7bc7db9SEric Garver else: 693bd128f62SAaron Conole actstr = actstr[len("drop"): ] 694bd128f62SAaron Conole return (totallen - len(actstr)) 695918423fdSAaron Conole 6963fde60afSAdrian Moreno elif parse_starts_block(actstr, r"^(\d+)", False, True): 697918423fdSAaron Conole actstr, output = parse_extract_field( 6983fde60afSAdrian Moreno actstr, None, r"(\d+)", lambda x: int(x), False, "0" 699918423fdSAaron Conole ) 700918423fdSAaron Conole self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output]) 701918423fdSAaron Conole parsed = True 702918423fdSAaron Conole elif parse_starts_block(actstr, "recirc(", False): 703918423fdSAaron Conole actstr, recircid = parse_extract_field( 704918423fdSAaron Conole actstr, 705918423fdSAaron Conole "recirc(", 7063fde60afSAdrian Moreno r"([0-9a-fA-Fx]+)", 707918423fdSAaron Conole lambda x: int(x, 0), 708918423fdSAaron Conole False, 709918423fdSAaron Conole 0, 710918423fdSAaron Conole ) 711bd128f62SAaron Conole parencount += 1 712918423fdSAaron Conole self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid]) 713918423fdSAaron Conole parsed = True 714918423fdSAaron Conole 715918423fdSAaron Conole parse_flat_map = ( 716918423fdSAaron Conole ("ct_clear", "OVS_ACTION_ATTR_CT_CLEAR"), 717918423fdSAaron Conole ("pop_vlan", "OVS_ACTION_ATTR_POP_VLAN"), 718918423fdSAaron Conole ("pop_eth", "OVS_ACTION_ATTR_POP_ETH"), 719918423fdSAaron Conole ("pop_nsh", "OVS_ACTION_ATTR_POP_NSH"), 720918423fdSAaron Conole ) 721918423fdSAaron Conole 722918423fdSAaron Conole for flat_act in parse_flat_map: 723918423fdSAaron Conole if parse_starts_block(actstr, flat_act[0], False): 724bd128f62SAaron Conole actstr = actstr[len(flat_act[0]):] 725a8763466SAdrian Moreno self["attrs"].append([flat_act[1], True]) 726918423fdSAaron Conole actstr = actstr[strspn(actstr, ", ") :] 727918423fdSAaron Conole parsed = True 728918423fdSAaron Conole 729bd128f62SAaron Conole if parse_starts_block(actstr, "clone(", False): 730bd128f62SAaron Conole parencount += 1 731bd128f62SAaron Conole subacts = ovsactions() 732bd128f62SAaron Conole actstr = actstr[len("clone("):] 733bd128f62SAaron Conole parsedLen = subacts.parse(actstr) 734bd128f62SAaron Conole lst = [] 735bd128f62SAaron Conole self["attrs"].append(("OVS_ACTION_ATTR_CLONE", subacts)) 736bd128f62SAaron Conole actstr = actstr[parsedLen:] 737bd128f62SAaron Conole parsed = True 738a4126f90SAaron Conole elif parse_starts_block(actstr, "set(", False): 739a4126f90SAaron Conole parencount += 1 740a4126f90SAaron Conole k = ovskey() 741a4126f90SAaron Conole actstr = actstr[len("set("):] 742a4126f90SAaron Conole actstr = k.parse(actstr, None) 743a4126f90SAaron Conole self["attrs"].append(("OVS_ACTION_ATTR_SET", k)) 744a4126f90SAaron Conole if not actstr.startswith(")"): 745a4126f90SAaron Conole actstr = ")" + actstr 746a4126f90SAaron Conole parsed = True 747a4126f90SAaron Conole elif parse_starts_block(actstr, "set_masked(", False): 748a4126f90SAaron Conole parencount += 1 749a4126f90SAaron Conole k = ovskey() 750a4126f90SAaron Conole m = ovskey() 751a4126f90SAaron Conole actstr = actstr[len("set_masked("):] 752a4126f90SAaron Conole actstr = k.parse(actstr, m) 753a4126f90SAaron Conole self["attrs"].append(("OVS_ACTION_ATTR_SET_MASKED", [k, m])) 754a4126f90SAaron Conole if not actstr.startswith(")"): 755a4126f90SAaron Conole actstr = ")" + actstr 756a4126f90SAaron Conole parsed = True 757bd128f62SAaron Conole elif parse_starts_block(actstr, "ct(", False): 758bd128f62SAaron Conole parencount += 1 7592893ba9cSAaron Conole actstr = actstr[len("ct(") :] 7602893ba9cSAaron Conole ctact = ovsactions.ctact() 7612893ba9cSAaron Conole 7622893ba9cSAaron Conole for scan in ( 7632893ba9cSAaron Conole ("commit", "OVS_CT_ATTR_COMMIT", None), 7642893ba9cSAaron Conole ("force_commit", "OVS_CT_ATTR_FORCE_COMMIT", None), 7652893ba9cSAaron Conole ("zone", "OVS_CT_ATTR_ZONE", int), 7662893ba9cSAaron Conole ("mark", "OVS_CT_ATTR_MARK", int), 7672893ba9cSAaron Conole ("helper", "OVS_CT_ATTR_HELPER", lambda x, y: str(x)), 7682893ba9cSAaron Conole ("timeout", "OVS_CT_ATTR_TIMEOUT", lambda x, y: str(x)), 7692893ba9cSAaron Conole ): 7702893ba9cSAaron Conole if actstr.startswith(scan[0]): 7712893ba9cSAaron Conole actstr = actstr[len(scan[0]) :] 7722893ba9cSAaron Conole if scan[2] is not None: 7732893ba9cSAaron Conole if actstr[0] != "=": 7742893ba9cSAaron Conole raise ValueError("Invalid ct attr") 7752893ba9cSAaron Conole actstr = actstr[1:] 7762893ba9cSAaron Conole pos = strcspn(actstr, ",)") 7772893ba9cSAaron Conole datum = scan[2](actstr[:pos], 0) 7782893ba9cSAaron Conole ctact["attrs"].append([scan[1], datum]) 7792893ba9cSAaron Conole actstr = actstr[pos:] 7802893ba9cSAaron Conole else: 7812893ba9cSAaron Conole ctact["attrs"].append([scan[1], None]) 7822893ba9cSAaron Conole actstr = actstr[strspn(actstr, ", ") :] 78360f10077SAaron Conole # it seems strange to put this here, but nat() is a complex 78460f10077SAaron Conole # sub-action and this lets it sit anywhere in the ct() action 78560f10077SAaron Conole if actstr.startswith("nat"): 78660f10077SAaron Conole actstr = actstr[3:] 78760f10077SAaron Conole natact = ovsactions.ctact.natattr() 78860f10077SAaron Conole 78960f10077SAaron Conole if actstr.startswith("("): 790bd128f62SAaron Conole parencount += 1 79160f10077SAaron Conole t = None 79260f10077SAaron Conole actstr = actstr[1:] 79360f10077SAaron Conole if actstr.startswith("src"): 79460f10077SAaron Conole t = "OVS_NAT_ATTR_SRC" 79560f10077SAaron Conole actstr = actstr[3:] 79660f10077SAaron Conole elif actstr.startswith("dst"): 79760f10077SAaron Conole t = "OVS_NAT_ATTR_DST" 79860f10077SAaron Conole actstr = actstr[3:] 79960f10077SAaron Conole 80060f10077SAaron Conole actstr, ip_block_min = parse_extract_field( 8013fde60afSAdrian Moreno actstr, "=", r"([0-9a-fA-F\.]+)", str, False 80260f10077SAaron Conole ) 80360f10077SAaron Conole actstr, ip_block_max = parse_extract_field( 8043fde60afSAdrian Moreno actstr, "-", r"([0-9a-fA-F\.]+)", str, False 80560f10077SAaron Conole ) 80660f10077SAaron Conole 80760f10077SAaron Conole actstr, proto_min = parse_extract_field( 8083fde60afSAdrian Moreno actstr, ":", r"(\d+)", int, False 80960f10077SAaron Conole ) 81060f10077SAaron Conole actstr, proto_max = parse_extract_field( 8113fde60afSAdrian Moreno actstr, "-", r"(\d+)", int, False 81260f10077SAaron Conole ) 81360f10077SAaron Conole 81460f10077SAaron Conole if t is not None: 81560f10077SAaron Conole natact["attrs"].append([t, None]) 81660f10077SAaron Conole 81760f10077SAaron Conole if ip_block_min is not None: 81860f10077SAaron Conole natact["attrs"].append( 81960f10077SAaron Conole ["OVS_NAT_ATTR_IP_MIN", ip_block_min] 82060f10077SAaron Conole ) 82160f10077SAaron Conole if ip_block_max is not None: 82260f10077SAaron Conole natact["attrs"].append( 82360f10077SAaron Conole ["OVS_NAT_ATTR_IP_MAX", ip_block_max] 82460f10077SAaron Conole ) 82560f10077SAaron Conole if proto_min is not None: 82660f10077SAaron Conole natact["attrs"].append( 82760f10077SAaron Conole ["OVS_NAT_ATTR_PROTO_MIN", proto_min] 82860f10077SAaron Conole ) 82960f10077SAaron Conole if proto_max is not None: 83060f10077SAaron Conole natact["attrs"].append( 83160f10077SAaron Conole ["OVS_NAT_ATTR_PROTO_MAX", proto_max] 83260f10077SAaron Conole ) 83360f10077SAaron Conole 83460f10077SAaron Conole for natscan in ( 83560f10077SAaron Conole ("persistent", "OVS_NAT_ATTR_PERSISTENT"), 83660f10077SAaron Conole ("hash", "OVS_NAT_ATTR_PROTO_HASH"), 83760f10077SAaron Conole ("random", "OVS_NAT_ATTR_PROTO_RANDOM"), 83860f10077SAaron Conole ): 83960f10077SAaron Conole if actstr.startswith(natscan[0]): 84060f10077SAaron Conole actstr = actstr[len(natscan[0]) :] 84160f10077SAaron Conole natact["attrs"].append([natscan[1], None]) 84260f10077SAaron Conole actstr = actstr[strspn(actstr, ", ") :] 84360f10077SAaron Conole 84460f10077SAaron Conole ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact]) 845bd128f62SAaron Conole actstr = actstr[strspn(actstr, ", ") :] 8462893ba9cSAaron Conole 8472893ba9cSAaron Conole self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact]) 8482893ba9cSAaron Conole parsed = True 8492893ba9cSAaron Conole 85060ccf62dSAdrian Moreno elif parse_starts_block(actstr, "sample(", False): 85160ccf62dSAdrian Moreno sampleact = self.sample() 85260ccf62dSAdrian Moreno actstr = sampleact.parse(actstr[len("sample(") : ]) 85360ccf62dSAdrian Moreno self["attrs"].append(["OVS_ACTION_ATTR_SAMPLE", sampleact]) 85460ccf62dSAdrian Moreno parsed = True 85560ccf62dSAdrian Moreno 85660ccf62dSAdrian Moreno elif parse_starts_block(actstr, "psample(", False): 85760ccf62dSAdrian Moreno psampleact = self.psample() 85860ccf62dSAdrian Moreno actstr = psampleact.parse(actstr[len("psample(") : ]) 85960ccf62dSAdrian Moreno self["attrs"].append(["OVS_ACTION_ATTR_PSAMPLE", psampleact]) 86060ccf62dSAdrian Moreno parsed = True 86160ccf62dSAdrian Moreno 862c7815abbSAdrian Moreno elif parse_starts_block(actstr, "userspace(", False): 863c7815abbSAdrian Moreno uact = self.userspace() 864c7815abbSAdrian Moreno actstr = uact.parse(actstr[len("userspace(") : ]) 865c7815abbSAdrian Moreno self["attrs"].append(["OVS_ACTION_ATTR_USERSPACE", uact]) 866c7815abbSAdrian Moreno parsed = True 867c7815abbSAdrian Moreno 868b192bf12SAdrian Moreno elif parse_starts_block(actstr, "trunc(", False): 869b192bf12SAdrian Moreno parencount += 1 870b192bf12SAdrian Moreno actstr, val = parse_extract_field( 871b192bf12SAdrian Moreno actstr, 872b192bf12SAdrian Moreno "trunc(", 873b192bf12SAdrian Moreno r"([0-9]+)", 874b192bf12SAdrian Moreno int, 875b192bf12SAdrian Moreno False, 876b192bf12SAdrian Moreno None, 877b192bf12SAdrian Moreno ) 878b192bf12SAdrian Moreno self["attrs"].append(["OVS_ACTION_ATTR_TRUNC", val]) 879b192bf12SAdrian Moreno parsed = True 880b192bf12SAdrian Moreno 881bd128f62SAaron Conole actstr = actstr[strspn(actstr, ", ") :] 882bd128f62SAaron Conole while parencount > 0: 883bd128f62SAaron Conole parencount -= 1 884bd128f62SAaron Conole actstr = actstr[strspn(actstr, " "):] 885bd128f62SAaron Conole if len(actstr) and actstr[0] != ")": 886bd128f62SAaron Conole raise ValueError("Action str: '%s' unbalanced" % actstr) 887bd128f62SAaron Conole actstr = actstr[1:] 888bd128f62SAaron Conole 889bd128f62SAaron Conole if len(actstr) and actstr[0] == ")": 890bd128f62SAaron Conole return (totallen - len(actstr)) 891bd128f62SAaron Conole 892bd128f62SAaron Conole actstr = actstr[strspn(actstr, ", ") :] 893bd128f62SAaron Conole 894918423fdSAaron Conole if not parsed: 895918423fdSAaron Conole raise ValueError("Action str: '%s' not supported" % actstr) 896918423fdSAaron Conole 897bd128f62SAaron Conole return (totallen - len(actstr)) 898bd128f62SAaron Conole 899e52b07aaSAaron Conole 900e52b07aaSAaron Conoleclass ovskey(nla): 901e52b07aaSAaron Conole nla_flags = NLA_F_NESTED 902e52b07aaSAaron Conole nla_map = ( 903e52b07aaSAaron Conole ("OVS_KEY_ATTR_UNSPEC", "none"), 904e52b07aaSAaron Conole ("OVS_KEY_ATTR_ENCAP", "none"), 905e52b07aaSAaron Conole ("OVS_KEY_ATTR_PRIORITY", "uint32"), 906e52b07aaSAaron Conole ("OVS_KEY_ATTR_IN_PORT", "uint32"), 907e52b07aaSAaron Conole ("OVS_KEY_ATTR_ETHERNET", "ethaddr"), 908e52b07aaSAaron Conole ("OVS_KEY_ATTR_VLAN", "uint16"), 909e52b07aaSAaron Conole ("OVS_KEY_ATTR_ETHERTYPE", "be16"), 910e52b07aaSAaron Conole ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"), 911e52b07aaSAaron Conole ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"), 912e52b07aaSAaron Conole ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"), 913e52b07aaSAaron Conole ("OVS_KEY_ATTR_UDP", "ovs_key_udp"), 914e52b07aaSAaron Conole ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"), 915e52b07aaSAaron Conole ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"), 916e52b07aaSAaron Conole ("OVS_KEY_ATTR_ARP", "ovs_key_arp"), 917e52b07aaSAaron Conole ("OVS_KEY_ATTR_ND", "ovs_key_nd"), 918e52b07aaSAaron Conole ("OVS_KEY_ATTR_SKB_MARK", "uint32"), 919fefe3b7dSAaron Conole ("OVS_KEY_ATTR_TUNNEL", "ovs_key_tunnel"), 920e52b07aaSAaron Conole ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"), 921e52b07aaSAaron Conole ("OVS_KEY_ATTR_TCP_FLAGS", "be16"), 922e52b07aaSAaron Conole ("OVS_KEY_ATTR_DP_HASH", "uint32"), 923e52b07aaSAaron Conole ("OVS_KEY_ATTR_RECIRC_ID", "uint32"), 924e52b07aaSAaron Conole ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"), 925e52b07aaSAaron Conole ("OVS_KEY_ATTR_CT_STATE", "uint32"), 926e52b07aaSAaron Conole ("OVS_KEY_ATTR_CT_ZONE", "uint16"), 927e52b07aaSAaron Conole ("OVS_KEY_ATTR_CT_MARK", "uint32"), 928e52b07aaSAaron Conole ("OVS_KEY_ATTR_CT_LABELS", "none"), 929e52b07aaSAaron Conole ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"), 930e52b07aaSAaron Conole ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"), 931e52b07aaSAaron Conole ("OVS_KEY_ATTR_NSH", "none"), 932e52b07aaSAaron Conole ("OVS_KEY_ATTR_PACKET_TYPE", "none"), 933e52b07aaSAaron Conole ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"), 934e52b07aaSAaron Conole ("OVS_KEY_ATTR_TUNNEL_INFO", "none"), 935e52b07aaSAaron Conole ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"), 936e52b07aaSAaron Conole ) 937e52b07aaSAaron Conole 938e52b07aaSAaron Conole class ovs_key_proto(nla): 939e52b07aaSAaron Conole fields = ( 940e52b07aaSAaron Conole ("src", "!H"), 941e52b07aaSAaron Conole ("dst", "!H"), 942e52b07aaSAaron Conole ) 943e52b07aaSAaron Conole 944e52b07aaSAaron Conole fields_map = ( 9459f1179fbSAdrian Moreno ("src", "src", "%d", lambda x: int(x) if x else 0, 9469f1179fbSAdrian Moreno convert_int(16)), 9479f1179fbSAdrian Moreno ("dst", "dst", "%d", lambda x: int(x) if x else 0, 9489f1179fbSAdrian Moreno convert_int(16)), 949e52b07aaSAaron Conole ) 950e52b07aaSAaron Conole 951e52b07aaSAaron Conole def __init__( 952e52b07aaSAaron Conole self, 953e52b07aaSAaron Conole protostr, 954e52b07aaSAaron Conole data=None, 955e52b07aaSAaron Conole offset=None, 956e52b07aaSAaron Conole parent=None, 957e52b07aaSAaron Conole length=None, 958e52b07aaSAaron Conole init=None, 959e52b07aaSAaron Conole ): 960e52b07aaSAaron Conole self.proto_str = protostr 961e52b07aaSAaron Conole nla.__init__( 962e52b07aaSAaron Conole self, 963e52b07aaSAaron Conole data=data, 964e52b07aaSAaron Conole offset=offset, 965e52b07aaSAaron Conole parent=parent, 966e52b07aaSAaron Conole length=length, 967e52b07aaSAaron Conole init=init, 968e52b07aaSAaron Conole ) 969e52b07aaSAaron Conole 970918423fdSAaron Conole def parse(self, flowstr, typeInst): 971918423fdSAaron Conole if not flowstr.startswith(self.proto_str): 972918423fdSAaron Conole return None, None 973918423fdSAaron Conole 974918423fdSAaron Conole k = typeInst() 975918423fdSAaron Conole m = typeInst() 976918423fdSAaron Conole 977918423fdSAaron Conole flowstr = flowstr[len(self.proto_str) :] 978918423fdSAaron Conole if flowstr.startswith("("): 979918423fdSAaron Conole flowstr = flowstr[1:] 980918423fdSAaron Conole 981918423fdSAaron Conole keybits = b"" 982918423fdSAaron Conole maskbits = b"" 983918423fdSAaron Conole for f in self.fields_map: 984918423fdSAaron Conole if flowstr.startswith(f[1]): 985918423fdSAaron Conole # the following assumes that the field looks 986918423fdSAaron Conole # something like 'field.' where '.' is a 987918423fdSAaron Conole # character that we don't exactly care about. 988918423fdSAaron Conole flowstr = flowstr[len(f[1]) + 1 :] 989918423fdSAaron Conole splitchar = 0 990918423fdSAaron Conole for c in flowstr: 991918423fdSAaron Conole if c == "," or c == ")": 992918423fdSAaron Conole break 993918423fdSAaron Conole splitchar += 1 994918423fdSAaron Conole data = flowstr[:splitchar] 995918423fdSAaron Conole flowstr = flowstr[splitchar:] 996918423fdSAaron Conole else: 9979f1179fbSAdrian Moreno data = "" 998918423fdSAaron Conole 999918423fdSAaron Conole if len(f) > 4: 10009f1179fbSAdrian Moreno k[f[0]], m[f[0]] = f[4](data) 1001918423fdSAaron Conole else: 10029f1179fbSAdrian Moreno k[f[0]] = f[3](data) 10039f1179fbSAdrian Moreno m[f[0]] = f[3](data) 1004918423fdSAaron Conole 1005918423fdSAaron Conole flowstr = flowstr[strspn(flowstr, ", ") :] 1006918423fdSAaron Conole if len(flowstr) == 0: 1007918423fdSAaron Conole return flowstr, k, m 1008918423fdSAaron Conole 1009918423fdSAaron Conole flowstr = flowstr[strspn(flowstr, "), ") :] 1010918423fdSAaron Conole 1011918423fdSAaron Conole return flowstr, k, m 1012918423fdSAaron Conole 1013e52b07aaSAaron Conole def dpstr(self, masked=None, more=False): 1014e52b07aaSAaron Conole outstr = self.proto_str + "(" 1015e52b07aaSAaron Conole first = False 1016e52b07aaSAaron Conole for f in self.fields_map: 1017e52b07aaSAaron Conole if first: 1018e52b07aaSAaron Conole outstr += "," 1019e52b07aaSAaron Conole if masked is None: 1020e52b07aaSAaron Conole outstr += "%s=" % f[0] 1021e52b07aaSAaron Conole if isinstance(f[2], str): 1022e52b07aaSAaron Conole outstr += f[2] % self[f[1]] 1023e52b07aaSAaron Conole else: 1024e52b07aaSAaron Conole outstr += f[2](self[f[1]]) 1025e52b07aaSAaron Conole first = True 1026e52b07aaSAaron Conole elif more or f[3](masked[f[1]]) != 0: 1027e52b07aaSAaron Conole outstr += "%s=" % f[0] 1028e52b07aaSAaron Conole if isinstance(f[2], str): 1029e52b07aaSAaron Conole outstr += f[2] % self[f[1]] 1030e52b07aaSAaron Conole else: 1031e52b07aaSAaron Conole outstr += f[2](self[f[1]]) 1032e52b07aaSAaron Conole outstr += "/" 1033e52b07aaSAaron Conole if isinstance(f[2], str): 1034e52b07aaSAaron Conole outstr += f[2] % masked[f[1]] 1035e52b07aaSAaron Conole else: 1036e52b07aaSAaron Conole outstr += f[2](masked[f[1]]) 1037e52b07aaSAaron Conole first = True 1038e52b07aaSAaron Conole outstr += ")" 1039e52b07aaSAaron Conole return outstr 1040e52b07aaSAaron Conole 1041e52b07aaSAaron Conole class ethaddr(ovs_key_proto): 1042e52b07aaSAaron Conole fields = ( 1043e52b07aaSAaron Conole ("src", "!6s"), 1044e52b07aaSAaron Conole ("dst", "!6s"), 1045e52b07aaSAaron Conole ) 1046e52b07aaSAaron Conole 1047e52b07aaSAaron Conole fields_map = ( 1048e52b07aaSAaron Conole ( 1049e52b07aaSAaron Conole "src", 1050e52b07aaSAaron Conole "src", 1051e52b07aaSAaron Conole macstr, 1052e52b07aaSAaron Conole lambda x: int.from_bytes(x, "big"), 1053e52b07aaSAaron Conole convert_mac, 1054e52b07aaSAaron Conole ), 1055e52b07aaSAaron Conole ( 1056e52b07aaSAaron Conole "dst", 1057e52b07aaSAaron Conole "dst", 1058e52b07aaSAaron Conole macstr, 1059e52b07aaSAaron Conole lambda x: int.from_bytes(x, "big"), 1060e52b07aaSAaron Conole convert_mac, 1061e52b07aaSAaron Conole ), 1062e52b07aaSAaron Conole ) 1063e52b07aaSAaron Conole 1064e52b07aaSAaron Conole def __init__( 1065e52b07aaSAaron Conole self, 1066e52b07aaSAaron Conole data=None, 1067e52b07aaSAaron Conole offset=None, 1068e52b07aaSAaron Conole parent=None, 1069e52b07aaSAaron Conole length=None, 1070e52b07aaSAaron Conole init=None, 1071e52b07aaSAaron Conole ): 1072e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1073e52b07aaSAaron Conole self, 1074e52b07aaSAaron Conole "eth", 1075e52b07aaSAaron Conole data=data, 1076e52b07aaSAaron Conole offset=offset, 1077e52b07aaSAaron Conole parent=parent, 1078e52b07aaSAaron Conole length=length, 1079e52b07aaSAaron Conole init=init, 1080e52b07aaSAaron Conole ) 1081e52b07aaSAaron Conole 1082e52b07aaSAaron Conole class ovs_key_ipv4(ovs_key_proto): 1083e52b07aaSAaron Conole fields = ( 1084e52b07aaSAaron Conole ("src", "!I"), 1085e52b07aaSAaron Conole ("dst", "!I"), 1086e52b07aaSAaron Conole ("proto", "B"), 1087e52b07aaSAaron Conole ("tos", "B"), 1088e52b07aaSAaron Conole ("ttl", "B"), 1089e52b07aaSAaron Conole ("frag", "B"), 1090e52b07aaSAaron Conole ) 1091e52b07aaSAaron Conole 1092e52b07aaSAaron Conole fields_map = ( 1093e52b07aaSAaron Conole ( 1094e52b07aaSAaron Conole "src", 1095e52b07aaSAaron Conole "src", 1096e52b07aaSAaron Conole lambda x: str(ipaddress.IPv4Address(x)), 1097e52b07aaSAaron Conole int, 1098e52b07aaSAaron Conole convert_ipv4, 1099e52b07aaSAaron Conole ), 1100e52b07aaSAaron Conole ( 1101e52b07aaSAaron Conole "dst", 1102e52b07aaSAaron Conole "dst", 1103e52b07aaSAaron Conole lambda x: str(ipaddress.IPv4Address(x)), 1104e52b07aaSAaron Conole int, 1105e52b07aaSAaron Conole convert_ipv4, 1106e52b07aaSAaron Conole ), 11079f1179fbSAdrian Moreno ("proto", "proto", "%d", lambda x: int(x) if x else 0, 11089f1179fbSAdrian Moreno convert_int(8)), 11099f1179fbSAdrian Moreno ("tos", "tos", "%d", lambda x: int(x) if x else 0, 11109f1179fbSAdrian Moreno convert_int(8)), 11119f1179fbSAdrian Moreno ("ttl", "ttl", "%d", lambda x: int(x) if x else 0, 11129f1179fbSAdrian Moreno convert_int(8)), 11139f1179fbSAdrian Moreno ("frag", "frag", "%d", lambda x: int(x) if x else 0, 11149f1179fbSAdrian Moreno convert_int(8)), 1115e52b07aaSAaron Conole ) 1116e52b07aaSAaron Conole 1117e52b07aaSAaron Conole def __init__( 1118e52b07aaSAaron Conole self, 1119e52b07aaSAaron Conole data=None, 1120e52b07aaSAaron Conole offset=None, 1121e52b07aaSAaron Conole parent=None, 1122e52b07aaSAaron Conole length=None, 1123e52b07aaSAaron Conole init=None, 1124e52b07aaSAaron Conole ): 1125e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1126e52b07aaSAaron Conole self, 1127e52b07aaSAaron Conole "ipv4", 1128e52b07aaSAaron Conole data=data, 1129e52b07aaSAaron Conole offset=offset, 1130e52b07aaSAaron Conole parent=parent, 1131e52b07aaSAaron Conole length=length, 1132e52b07aaSAaron Conole init=init, 1133e52b07aaSAaron Conole ) 1134e52b07aaSAaron Conole 1135e52b07aaSAaron Conole class ovs_key_ipv6(ovs_key_proto): 1136e52b07aaSAaron Conole fields = ( 1137e52b07aaSAaron Conole ("src", "!16s"), 1138e52b07aaSAaron Conole ("dst", "!16s"), 1139e52b07aaSAaron Conole ("label", "!I"), 1140e52b07aaSAaron Conole ("proto", "B"), 1141e52b07aaSAaron Conole ("tclass", "B"), 1142e52b07aaSAaron Conole ("hlimit", "B"), 1143e52b07aaSAaron Conole ("frag", "B"), 1144e52b07aaSAaron Conole ) 1145e52b07aaSAaron Conole 1146e52b07aaSAaron Conole fields_map = ( 1147e52b07aaSAaron Conole ( 1148e52b07aaSAaron Conole "src", 1149e52b07aaSAaron Conole "src", 1150e52b07aaSAaron Conole lambda x: str(ipaddress.IPv6Address(x)), 115151458e10SAaron Conole lambda x: ipaddress.IPv6Address(x).packed if x else 0, 115251458e10SAaron Conole convert_ipv6, 1153e52b07aaSAaron Conole ), 1154e52b07aaSAaron Conole ( 1155e52b07aaSAaron Conole "dst", 1156e52b07aaSAaron Conole "dst", 1157e52b07aaSAaron Conole lambda x: str(ipaddress.IPv6Address(x)), 115851458e10SAaron Conole lambda x: ipaddress.IPv6Address(x).packed if x else 0, 115951458e10SAaron Conole convert_ipv6, 1160e52b07aaSAaron Conole ), 116151458e10SAaron Conole ("label", "label", "%d", lambda x: int(x) if x else 0), 116251458e10SAaron Conole ("proto", "proto", "%d", lambda x: int(x) if x else 0), 116351458e10SAaron Conole ("tclass", "tclass", "%d", lambda x: int(x) if x else 0), 116451458e10SAaron Conole ("hlimit", "hlimit", "%d", lambda x: int(x) if x else 0), 116551458e10SAaron Conole ("frag", "frag", "%d", lambda x: int(x) if x else 0), 1166e52b07aaSAaron Conole ) 1167e52b07aaSAaron Conole 1168e52b07aaSAaron Conole def __init__( 1169e52b07aaSAaron Conole self, 1170e52b07aaSAaron Conole data=None, 1171e52b07aaSAaron Conole offset=None, 1172e52b07aaSAaron Conole parent=None, 1173e52b07aaSAaron Conole length=None, 1174e52b07aaSAaron Conole init=None, 1175e52b07aaSAaron Conole ): 1176e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1177e52b07aaSAaron Conole self, 1178e52b07aaSAaron Conole "ipv6", 1179e52b07aaSAaron Conole data=data, 1180e52b07aaSAaron Conole offset=offset, 1181e52b07aaSAaron Conole parent=parent, 1182e52b07aaSAaron Conole length=length, 1183e52b07aaSAaron Conole init=init, 1184e52b07aaSAaron Conole ) 1185e52b07aaSAaron Conole 1186e52b07aaSAaron Conole class ovs_key_tcp(ovs_key_proto): 1187e52b07aaSAaron Conole def __init__( 1188e52b07aaSAaron Conole self, 1189e52b07aaSAaron Conole data=None, 1190e52b07aaSAaron Conole offset=None, 1191e52b07aaSAaron Conole parent=None, 1192e52b07aaSAaron Conole length=None, 1193e52b07aaSAaron Conole init=None, 1194e52b07aaSAaron Conole ): 1195e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1196e52b07aaSAaron Conole self, 1197e52b07aaSAaron Conole "tcp", 1198e52b07aaSAaron Conole data=data, 1199e52b07aaSAaron Conole offset=offset, 1200e52b07aaSAaron Conole parent=parent, 1201e52b07aaSAaron Conole length=length, 1202e52b07aaSAaron Conole init=init, 1203e52b07aaSAaron Conole ) 1204e52b07aaSAaron Conole 1205e52b07aaSAaron Conole class ovs_key_udp(ovs_key_proto): 1206e52b07aaSAaron Conole def __init__( 1207e52b07aaSAaron Conole self, 1208e52b07aaSAaron Conole data=None, 1209e52b07aaSAaron Conole offset=None, 1210e52b07aaSAaron Conole parent=None, 1211e52b07aaSAaron Conole length=None, 1212e52b07aaSAaron Conole init=None, 1213e52b07aaSAaron Conole ): 1214e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1215e52b07aaSAaron Conole self, 1216e52b07aaSAaron Conole "udp", 1217e52b07aaSAaron Conole data=data, 1218e52b07aaSAaron Conole offset=offset, 1219e52b07aaSAaron Conole parent=parent, 1220e52b07aaSAaron Conole length=length, 1221e52b07aaSAaron Conole init=init, 1222e52b07aaSAaron Conole ) 1223e52b07aaSAaron Conole 1224e52b07aaSAaron Conole class ovs_key_sctp(ovs_key_proto): 1225e52b07aaSAaron Conole def __init__( 1226e52b07aaSAaron Conole self, 1227e52b07aaSAaron Conole data=None, 1228e52b07aaSAaron Conole offset=None, 1229e52b07aaSAaron Conole parent=None, 1230e52b07aaSAaron Conole length=None, 1231e52b07aaSAaron Conole init=None, 1232e52b07aaSAaron Conole ): 1233e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1234e52b07aaSAaron Conole self, 1235e52b07aaSAaron Conole "sctp", 1236e52b07aaSAaron Conole data=data, 1237e52b07aaSAaron Conole offset=offset, 1238e52b07aaSAaron Conole parent=parent, 1239e52b07aaSAaron Conole length=length, 1240e52b07aaSAaron Conole init=init, 1241e52b07aaSAaron Conole ) 1242e52b07aaSAaron Conole 1243e52b07aaSAaron Conole class ovs_key_icmp(ovs_key_proto): 1244e52b07aaSAaron Conole fields = ( 1245e52b07aaSAaron Conole ("type", "B"), 1246e52b07aaSAaron Conole ("code", "B"), 1247e52b07aaSAaron Conole ) 1248e52b07aaSAaron Conole 1249e52b07aaSAaron Conole fields_map = ( 12509f1179fbSAdrian Moreno ("type", "type", "%d", lambda x: int(x) if x else 0), 12519f1179fbSAdrian Moreno ("code", "code", "%d", lambda x: int(x) if x else 0), 1252e52b07aaSAaron Conole ) 1253e52b07aaSAaron Conole 1254e52b07aaSAaron Conole def __init__( 1255e52b07aaSAaron Conole self, 1256e52b07aaSAaron Conole data=None, 1257e52b07aaSAaron Conole offset=None, 1258e52b07aaSAaron Conole parent=None, 1259e52b07aaSAaron Conole length=None, 1260e52b07aaSAaron Conole init=None, 1261e52b07aaSAaron Conole ): 1262e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1263e52b07aaSAaron Conole self, 1264e52b07aaSAaron Conole "icmp", 1265e52b07aaSAaron Conole data=data, 1266e52b07aaSAaron Conole offset=offset, 1267e52b07aaSAaron Conole parent=parent, 1268e52b07aaSAaron Conole length=length, 1269e52b07aaSAaron Conole init=init, 1270e52b07aaSAaron Conole ) 1271e52b07aaSAaron Conole 1272e52b07aaSAaron Conole class ovs_key_icmpv6(ovs_key_icmp): 1273e52b07aaSAaron Conole def __init__( 1274e52b07aaSAaron Conole self, 1275e52b07aaSAaron Conole data=None, 1276e52b07aaSAaron Conole offset=None, 1277e52b07aaSAaron Conole parent=None, 1278e52b07aaSAaron Conole length=None, 1279e52b07aaSAaron Conole init=None, 1280e52b07aaSAaron Conole ): 1281e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1282e52b07aaSAaron Conole self, 1283e52b07aaSAaron Conole "icmpv6", 1284e52b07aaSAaron Conole data=data, 1285e52b07aaSAaron Conole offset=offset, 1286e52b07aaSAaron Conole parent=parent, 1287e52b07aaSAaron Conole length=length, 1288e52b07aaSAaron Conole init=init, 1289e52b07aaSAaron Conole ) 1290e52b07aaSAaron Conole 1291e52b07aaSAaron Conole class ovs_key_arp(ovs_key_proto): 1292e52b07aaSAaron Conole fields = ( 1293e52b07aaSAaron Conole ("sip", "!I"), 1294e52b07aaSAaron Conole ("tip", "!I"), 1295e52b07aaSAaron Conole ("op", "!H"), 1296e52b07aaSAaron Conole ("sha", "!6s"), 1297e52b07aaSAaron Conole ("tha", "!6s"), 1298e52b07aaSAaron Conole ("pad", "xx"), 1299e52b07aaSAaron Conole ) 1300e52b07aaSAaron Conole 1301e52b07aaSAaron Conole fields_map = ( 1302e52b07aaSAaron Conole ( 1303e52b07aaSAaron Conole "sip", 1304e52b07aaSAaron Conole "sip", 1305e52b07aaSAaron Conole lambda x: str(ipaddress.IPv4Address(x)), 1306e52b07aaSAaron Conole int, 1307e52b07aaSAaron Conole convert_ipv4, 1308e52b07aaSAaron Conole ), 1309e52b07aaSAaron Conole ( 1310e52b07aaSAaron Conole "tip", 1311e52b07aaSAaron Conole "tip", 1312e52b07aaSAaron Conole lambda x: str(ipaddress.IPv4Address(x)), 1313e52b07aaSAaron Conole int, 1314e52b07aaSAaron Conole convert_ipv4, 1315e52b07aaSAaron Conole ), 13169f1179fbSAdrian Moreno ("op", "op", "%d", lambda x: int(x) if x else 0), 1317e52b07aaSAaron Conole ( 1318e52b07aaSAaron Conole "sha", 1319e52b07aaSAaron Conole "sha", 1320e52b07aaSAaron Conole macstr, 1321e52b07aaSAaron Conole lambda x: int.from_bytes(x, "big"), 1322e52b07aaSAaron Conole convert_mac, 1323e52b07aaSAaron Conole ), 1324e52b07aaSAaron Conole ( 1325e52b07aaSAaron Conole "tha", 1326e52b07aaSAaron Conole "tha", 1327e52b07aaSAaron Conole macstr, 1328e52b07aaSAaron Conole lambda x: int.from_bytes(x, "big"), 1329e52b07aaSAaron Conole convert_mac, 1330e52b07aaSAaron Conole ), 1331e52b07aaSAaron Conole ) 1332e52b07aaSAaron Conole 1333e52b07aaSAaron Conole def __init__( 1334e52b07aaSAaron Conole self, 1335e52b07aaSAaron Conole data=None, 1336e52b07aaSAaron Conole offset=None, 1337e52b07aaSAaron Conole parent=None, 1338e52b07aaSAaron Conole length=None, 1339e52b07aaSAaron Conole init=None, 1340e52b07aaSAaron Conole ): 1341e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1342e52b07aaSAaron Conole self, 1343e52b07aaSAaron Conole "arp", 1344e52b07aaSAaron Conole data=data, 1345e52b07aaSAaron Conole offset=offset, 1346e52b07aaSAaron Conole parent=parent, 1347e52b07aaSAaron Conole length=length, 1348e52b07aaSAaron Conole init=init, 1349e52b07aaSAaron Conole ) 1350e52b07aaSAaron Conole 1351e52b07aaSAaron Conole class ovs_key_nd(ovs_key_proto): 1352e52b07aaSAaron Conole fields = ( 1353e52b07aaSAaron Conole ("target", "!16s"), 1354e52b07aaSAaron Conole ("sll", "!6s"), 1355e52b07aaSAaron Conole ("tll", "!6s"), 1356e52b07aaSAaron Conole ) 1357e52b07aaSAaron Conole 1358e52b07aaSAaron Conole fields_map = ( 1359e52b07aaSAaron Conole ( 1360e52b07aaSAaron Conole "target", 1361e52b07aaSAaron Conole "target", 1362e52b07aaSAaron Conole lambda x: str(ipaddress.IPv6Address(x)), 136351458e10SAaron Conole convert_ipv6, 1364e52b07aaSAaron Conole ), 1365e52b07aaSAaron Conole ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")), 1366e52b07aaSAaron Conole ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")), 1367e52b07aaSAaron Conole ) 1368e52b07aaSAaron Conole 1369e52b07aaSAaron Conole def __init__( 1370e52b07aaSAaron Conole self, 1371e52b07aaSAaron Conole data=None, 1372e52b07aaSAaron Conole offset=None, 1373e52b07aaSAaron Conole parent=None, 1374e52b07aaSAaron Conole length=None, 1375e52b07aaSAaron Conole init=None, 1376e52b07aaSAaron Conole ): 1377e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1378e52b07aaSAaron Conole self, 1379e52b07aaSAaron Conole "nd", 1380e52b07aaSAaron Conole data=data, 1381e52b07aaSAaron Conole offset=offset, 1382e52b07aaSAaron Conole parent=parent, 1383e52b07aaSAaron Conole length=length, 1384e52b07aaSAaron Conole init=init, 1385e52b07aaSAaron Conole ) 1386e52b07aaSAaron Conole 1387e52b07aaSAaron Conole class ovs_key_ct_tuple_ipv4(ovs_key_proto): 1388e52b07aaSAaron Conole fields = ( 1389e52b07aaSAaron Conole ("src", "!I"), 1390e52b07aaSAaron Conole ("dst", "!I"), 1391e52b07aaSAaron Conole ("tp_src", "!H"), 1392e52b07aaSAaron Conole ("tp_dst", "!H"), 1393e52b07aaSAaron Conole ("proto", "B"), 1394e52b07aaSAaron Conole ) 1395e52b07aaSAaron Conole 1396e52b07aaSAaron Conole fields_map = ( 1397e52b07aaSAaron Conole ( 1398e52b07aaSAaron Conole "src", 1399e52b07aaSAaron Conole "src", 1400e52b07aaSAaron Conole lambda x: str(ipaddress.IPv4Address(x)), 1401e52b07aaSAaron Conole int, 14028eff0e06SAaron Conole convert_ipv4, 1403e52b07aaSAaron Conole ), 1404e52b07aaSAaron Conole ( 1405e52b07aaSAaron Conole "dst", 1406e52b07aaSAaron Conole "dst", 14078eff0e06SAaron Conole lambda x: str(ipaddress.IPv4Address(x)), 1408e52b07aaSAaron Conole int, 14098eff0e06SAaron Conole convert_ipv4, 1410e52b07aaSAaron Conole ), 1411e52b07aaSAaron Conole ("tp_src", "tp_src", "%d", int), 1412e52b07aaSAaron Conole ("tp_dst", "tp_dst", "%d", int), 1413e52b07aaSAaron Conole ("proto", "proto", "%d", int), 1414e52b07aaSAaron Conole ) 1415e52b07aaSAaron Conole 1416e52b07aaSAaron Conole def __init__( 1417e52b07aaSAaron Conole self, 1418e52b07aaSAaron Conole data=None, 1419e52b07aaSAaron Conole offset=None, 1420e52b07aaSAaron Conole parent=None, 1421e52b07aaSAaron Conole length=None, 1422e52b07aaSAaron Conole init=None, 1423e52b07aaSAaron Conole ): 1424e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1425e52b07aaSAaron Conole self, 1426e52b07aaSAaron Conole "ct_tuple4", 1427e52b07aaSAaron Conole data=data, 1428e52b07aaSAaron Conole offset=offset, 1429e52b07aaSAaron Conole parent=parent, 1430e52b07aaSAaron Conole length=length, 1431e52b07aaSAaron Conole init=init, 1432e52b07aaSAaron Conole ) 1433e52b07aaSAaron Conole 1434e52b07aaSAaron Conole class ovs_key_ct_tuple_ipv6(nla): 1435e52b07aaSAaron Conole fields = ( 1436e52b07aaSAaron Conole ("src", "!16s"), 1437e52b07aaSAaron Conole ("dst", "!16s"), 1438e52b07aaSAaron Conole ("tp_src", "!H"), 1439e52b07aaSAaron Conole ("tp_dst", "!H"), 1440e52b07aaSAaron Conole ("proto", "B"), 1441e52b07aaSAaron Conole ) 1442e52b07aaSAaron Conole 1443e52b07aaSAaron Conole fields_map = ( 1444e52b07aaSAaron Conole ( 1445e52b07aaSAaron Conole "src", 1446e52b07aaSAaron Conole "src", 1447e52b07aaSAaron Conole lambda x: str(ipaddress.IPv6Address(x)), 144851458e10SAaron Conole convert_ipv6, 1449e52b07aaSAaron Conole ), 1450e52b07aaSAaron Conole ( 1451e52b07aaSAaron Conole "dst", 1452e52b07aaSAaron Conole "dst", 1453e52b07aaSAaron Conole lambda x: str(ipaddress.IPv6Address(x)), 145451458e10SAaron Conole convert_ipv6, 1455e52b07aaSAaron Conole ), 1456e52b07aaSAaron Conole ("tp_src", "tp_src", "%d", int), 1457e52b07aaSAaron Conole ("tp_dst", "tp_dst", "%d", int), 1458e52b07aaSAaron Conole ("proto", "proto", "%d", int), 1459e52b07aaSAaron Conole ) 1460e52b07aaSAaron Conole 1461e52b07aaSAaron Conole def __init__( 1462e52b07aaSAaron Conole self, 1463e52b07aaSAaron Conole data=None, 1464e52b07aaSAaron Conole offset=None, 1465e52b07aaSAaron Conole parent=None, 1466e52b07aaSAaron Conole length=None, 1467e52b07aaSAaron Conole init=None, 1468e52b07aaSAaron Conole ): 1469e52b07aaSAaron Conole ovskey.ovs_key_proto.__init__( 1470e52b07aaSAaron Conole self, 1471e52b07aaSAaron Conole "ct_tuple6", 1472e52b07aaSAaron Conole data=data, 1473e52b07aaSAaron Conole offset=offset, 1474e52b07aaSAaron Conole parent=parent, 1475e52b07aaSAaron Conole length=length, 1476e52b07aaSAaron Conole init=init, 1477e52b07aaSAaron Conole ) 1478e52b07aaSAaron Conole 1479fefe3b7dSAaron Conole class ovs_key_tunnel(nla): 1480fefe3b7dSAaron Conole nla_flags = NLA_F_NESTED 1481fefe3b7dSAaron Conole 1482fefe3b7dSAaron Conole nla_map = ( 1483fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_ID", "be64"), 1484fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_IPV4_SRC", "ipaddr"), 1485fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_IPV4_DST", "ipaddr"), 1486fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_TOS", "uint8"), 1487fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_TTL", "uint8"), 1488fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT", "flag"), 1489fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_CSUM", "flag"), 1490fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_OAM", "flag"), 1491fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS", "array(uint32)"), 1492fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_TP_SRC", "be16"), 1493fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_TP_DST", "be16"), 1494fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS", "none"), 1495fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_IPV6_SRC", "ipaddr"), 1496fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_IPV6_DST", "ipaddr"), 1497fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_PAD", "none"), 1498fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS", "none"), 1499fefe3b7dSAaron Conole ("OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE", "flag"), 1500fefe3b7dSAaron Conole ) 1501fefe3b7dSAaron Conole 1502fefe3b7dSAaron Conole def parse(self, flowstr, mask=None): 1503fefe3b7dSAaron Conole if not flowstr.startswith("tunnel("): 1504fefe3b7dSAaron Conole return None, None 1505fefe3b7dSAaron Conole 1506fefe3b7dSAaron Conole k = ovskey.ovs_key_tunnel() 1507fefe3b7dSAaron Conole if mask is not None: 1508fefe3b7dSAaron Conole mask = ovskey.ovs_key_tunnel() 1509fefe3b7dSAaron Conole 1510fefe3b7dSAaron Conole flowstr = flowstr[len("tunnel("):] 1511fefe3b7dSAaron Conole 1512fefe3b7dSAaron Conole v6_address = None 1513fefe3b7dSAaron Conole 1514fefe3b7dSAaron Conole fields = [ 1515fefe3b7dSAaron Conole ("tun_id=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_ID", 1516fefe3b7dSAaron Conole 0xffffffffffffffff, None, None), 1517fefe3b7dSAaron Conole 1518fefe3b7dSAaron Conole ("src=", r"([0-9a-fA-F\.]+)", str, 1519fefe3b7dSAaron Conole "OVS_TUNNEL_KEY_ATTR_IPV4_SRC", "255.255.255.255", "0.0.0.0", 1520fefe3b7dSAaron Conole False), 1521fefe3b7dSAaron Conole ("dst=", r"([0-9a-fA-F\.]+)", str, 1522fefe3b7dSAaron Conole "OVS_TUNNEL_KEY_ATTR_IPV4_DST", "255.255.255.255", "0.0.0.0", 1523fefe3b7dSAaron Conole False), 1524fefe3b7dSAaron Conole 1525fefe3b7dSAaron Conole ("ipv6_src=", r"([0-9a-fA-F:]+)", str, 1526fefe3b7dSAaron Conole "OVS_TUNNEL_KEY_ATTR_IPV6_SRC", 1527fefe3b7dSAaron Conole "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "::", True), 1528fefe3b7dSAaron Conole ("ipv6_dst=", r"([0-9a-fA-F:]+)", str, 1529fefe3b7dSAaron Conole "OVS_TUNNEL_KEY_ATTR_IPV6_DST", 1530fefe3b7dSAaron Conole "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "::", True), 1531fefe3b7dSAaron Conole 1532fefe3b7dSAaron Conole ("tos=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TOS", 255, 0, 1533fefe3b7dSAaron Conole None), 1534fefe3b7dSAaron Conole ("ttl=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TTL", 255, 0, 1535fefe3b7dSAaron Conole None), 1536fefe3b7dSAaron Conole 1537fefe3b7dSAaron Conole ("tp_src=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TP_SRC", 1538fefe3b7dSAaron Conole 65535, 0, None), 1539fefe3b7dSAaron Conole ("tp_dst=", r"(\d+)", int, "OVS_TUNNEL_KEY_ATTR_TP_DST", 1540fefe3b7dSAaron Conole 65535, 0, None), 1541fefe3b7dSAaron Conole ] 1542fefe3b7dSAaron Conole 1543fefe3b7dSAaron Conole forced_include = ["OVS_TUNNEL_KEY_ATTR_TTL"] 1544fefe3b7dSAaron Conole 1545fefe3b7dSAaron Conole for prefix, regex, typ, attr_name, mask_val, default_val, v46_flag in fields: 1546fefe3b7dSAaron Conole flowstr, value = parse_extract_field(flowstr, prefix, regex, typ, False) 1547fefe3b7dSAaron Conole if not attr_name: 1548fefe3b7dSAaron Conole raise Exception("Bad list value in tunnel fields") 1549fefe3b7dSAaron Conole 1550fefe3b7dSAaron Conole if value is None and attr_name in forced_include: 1551fefe3b7dSAaron Conole value = default_val 1552fefe3b7dSAaron Conole mask_val = default_val 1553fefe3b7dSAaron Conole 1554fefe3b7dSAaron Conole if value is not None: 1555fefe3b7dSAaron Conole if v46_flag is not None: 1556fefe3b7dSAaron Conole if v6_address is None: 1557fefe3b7dSAaron Conole v6_address = v46_flag 1558fefe3b7dSAaron Conole if v46_flag != v6_address: 1559fefe3b7dSAaron Conole raise ValueError("Cannot mix v6 and v4 addresses") 1560fefe3b7dSAaron Conole k["attrs"].append([attr_name, value]) 1561fefe3b7dSAaron Conole if mask is not None: 1562fefe3b7dSAaron Conole mask["attrs"].append([attr_name, mask_val]) 1563fefe3b7dSAaron Conole else: 1564fefe3b7dSAaron Conole if v46_flag is not None: 1565fefe3b7dSAaron Conole if v6_address is None or v46_flag != v6_address: 1566fefe3b7dSAaron Conole continue 1567fefe3b7dSAaron Conole if mask is not None: 1568fefe3b7dSAaron Conole mask["attrs"].append([attr_name, default_val]) 1569fefe3b7dSAaron Conole 1570fefe3b7dSAaron Conole if k["attrs"][0][0] != "OVS_TUNNEL_KEY_ATTR_ID": 1571fefe3b7dSAaron Conole raise ValueError("Needs a tunid set") 1572fefe3b7dSAaron Conole 1573fefe3b7dSAaron Conole if flowstr.startswith("flags("): 1574fefe3b7dSAaron Conole flowstr = flowstr[len("flags("):] 1575fefe3b7dSAaron Conole flagspos = flowstr.find(")") 1576fefe3b7dSAaron Conole flags = flowstr[:flagspos] 1577fefe3b7dSAaron Conole flowstr = flowstr[flagspos + 1:] 1578fefe3b7dSAaron Conole 1579fefe3b7dSAaron Conole flag_attrs = { 1580fefe3b7dSAaron Conole "df": "OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT", 1581fefe3b7dSAaron Conole "csum": "OVS_TUNNEL_KEY_ATTR_CSUM", 1582fefe3b7dSAaron Conole "oam": "OVS_TUNNEL_KEY_ATTR_OAM" 1583fefe3b7dSAaron Conole } 1584fefe3b7dSAaron Conole 1585fefe3b7dSAaron Conole for flag in flags.split("|"): 1586fefe3b7dSAaron Conole if flag in flag_attrs: 1587fefe3b7dSAaron Conole k["attrs"].append([flag_attrs[flag], True]) 1588fefe3b7dSAaron Conole if mask is not None: 1589fefe3b7dSAaron Conole mask["attrs"].append([flag_attrs[flag], True]) 1590fefe3b7dSAaron Conole 1591fefe3b7dSAaron Conole flowstr = flowstr[strspn(flowstr, ", ") :] 1592fefe3b7dSAaron Conole return flowstr, k, mask 1593fefe3b7dSAaron Conole 1594fefe3b7dSAaron Conole def dpstr(self, mask=None, more=False): 1595fefe3b7dSAaron Conole print_str = "tunnel(" 1596fefe3b7dSAaron Conole 1597fefe3b7dSAaron Conole flagsattrs = [] 1598fefe3b7dSAaron Conole for k in self["attrs"]: 1599fefe3b7dSAaron Conole noprint = False 1600fefe3b7dSAaron Conole if k[0] == "OVS_TUNNEL_KEY_ATTR_ID": 1601fefe3b7dSAaron Conole print_str += "tun_id=%d" % k[1] 1602fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV4_SRC": 1603fefe3b7dSAaron Conole print_str += "src=%s" % k[1] 1604fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV4_DST": 1605fefe3b7dSAaron Conole print_str += "dst=%s" % k[1] 1606fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV6_SRC": 1607fefe3b7dSAaron Conole print_str += "ipv6_src=%s" % k[1] 1608fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_IPV6_DST": 1609fefe3b7dSAaron Conole print_str += "ipv6_dst=%s" % k[1] 1610fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_TOS": 1611fefe3b7dSAaron Conole print_str += "tos=%d" % k[1] 1612fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_TTL": 1613fefe3b7dSAaron Conole print_str += "ttl=%d" % k[1] 1614fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_TP_SRC": 1615fefe3b7dSAaron Conole print_str += "tp_src=%d" % k[1] 1616fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_TP_DST": 1617fefe3b7dSAaron Conole print_str += "tp_dst=%d" % k[1] 1618fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT": 1619fefe3b7dSAaron Conole noprint = True 1620fefe3b7dSAaron Conole flagsattrs.append("df") 1621fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_CSUM": 1622fefe3b7dSAaron Conole noprint = True 1623fefe3b7dSAaron Conole flagsattrs.append("csum") 1624fefe3b7dSAaron Conole elif k[0] == "OVS_TUNNEL_KEY_ATTR_OAM": 1625fefe3b7dSAaron Conole noprint = True 1626fefe3b7dSAaron Conole flagsattrs.append("oam") 1627fefe3b7dSAaron Conole 1628fefe3b7dSAaron Conole if not noprint: 1629fefe3b7dSAaron Conole print_str += "," 1630fefe3b7dSAaron Conole 1631fefe3b7dSAaron Conole if len(flagsattrs): 1632fefe3b7dSAaron Conole print_str += "flags(" + "|".join(flagsattrs) + ")" 1633fefe3b7dSAaron Conole print_str += ")" 1634fefe3b7dSAaron Conole return print_str 1635fefe3b7dSAaron Conole 1636e52b07aaSAaron Conole class ovs_key_mpls(nla): 1637e52b07aaSAaron Conole fields = (("lse", ">I"),) 1638e52b07aaSAaron Conole 1639918423fdSAaron Conole def parse(self, flowstr, mask=None): 1640918423fdSAaron Conole for field in ( 1641918423fdSAaron Conole ("OVS_KEY_ATTR_PRIORITY", "skb_priority", intparse), 1642918423fdSAaron Conole ("OVS_KEY_ATTR_SKB_MARK", "skb_mark", intparse), 1643918423fdSAaron Conole ("OVS_KEY_ATTR_RECIRC_ID", "recirc_id", intparse), 1644fefe3b7dSAaron Conole ("OVS_KEY_ATTR_TUNNEL", "tunnel", ovskey.ovs_key_tunnel), 1645918423fdSAaron Conole ("OVS_KEY_ATTR_DP_HASH", "dp_hash", intparse), 1646918423fdSAaron Conole ("OVS_KEY_ATTR_CT_STATE", "ct_state", parse_ct_state), 1647918423fdSAaron Conole ("OVS_KEY_ATTR_CT_ZONE", "ct_zone", intparse), 1648918423fdSAaron Conole ("OVS_KEY_ATTR_CT_MARK", "ct_mark", intparse), 1649918423fdSAaron Conole ("OVS_KEY_ATTR_IN_PORT", "in_port", intparse), 1650918423fdSAaron Conole ( 1651918423fdSAaron Conole "OVS_KEY_ATTR_ETHERNET", 1652918423fdSAaron Conole "eth", 1653918423fdSAaron Conole ovskey.ethaddr, 1654918423fdSAaron Conole ), 1655918423fdSAaron Conole ( 1656918423fdSAaron Conole "OVS_KEY_ATTR_ETHERTYPE", 1657918423fdSAaron Conole "eth_type", 1658918423fdSAaron Conole lambda x: intparse(x, "0xffff"), 1659918423fdSAaron Conole ), 1660918423fdSAaron Conole ( 1661918423fdSAaron Conole "OVS_KEY_ATTR_IPV4", 1662918423fdSAaron Conole "ipv4", 1663918423fdSAaron Conole ovskey.ovs_key_ipv4, 1664918423fdSAaron Conole ), 1665918423fdSAaron Conole ( 1666918423fdSAaron Conole "OVS_KEY_ATTR_IPV6", 1667918423fdSAaron Conole "ipv6", 1668918423fdSAaron Conole ovskey.ovs_key_ipv6, 1669918423fdSAaron Conole ), 1670918423fdSAaron Conole ( 1671918423fdSAaron Conole "OVS_KEY_ATTR_ARP", 1672918423fdSAaron Conole "arp", 1673918423fdSAaron Conole ovskey.ovs_key_arp, 1674918423fdSAaron Conole ), 1675918423fdSAaron Conole ( 1676918423fdSAaron Conole "OVS_KEY_ATTR_TCP", 1677918423fdSAaron Conole "tcp", 1678918423fdSAaron Conole ovskey.ovs_key_tcp, 1679918423fdSAaron Conole ), 1680918423fdSAaron Conole ( 16819f1179fbSAdrian Moreno "OVS_KEY_ATTR_UDP", 16829f1179fbSAdrian Moreno "udp", 16839f1179fbSAdrian Moreno ovskey.ovs_key_udp, 16849f1179fbSAdrian Moreno ), 16859f1179fbSAdrian Moreno ( 16869f1179fbSAdrian Moreno "OVS_KEY_ATTR_ICMP", 16879f1179fbSAdrian Moreno "icmp", 16889f1179fbSAdrian Moreno ovskey.ovs_key_icmp, 16899f1179fbSAdrian Moreno ), 16909f1179fbSAdrian Moreno ( 1691918423fdSAaron Conole "OVS_KEY_ATTR_TCP_FLAGS", 1692918423fdSAaron Conole "tcp_flags", 1693918423fdSAaron Conole lambda x: parse_flags(x, None), 1694918423fdSAaron Conole ), 1695918423fdSAaron Conole ): 1696918423fdSAaron Conole fld = field[1] + "(" 1697918423fdSAaron Conole if not flowstr.startswith(fld): 1698918423fdSAaron Conole continue 1699918423fdSAaron Conole 1700918423fdSAaron Conole if not isinstance(field[2], types.FunctionType): 1701918423fdSAaron Conole nk = field[2]() 1702918423fdSAaron Conole flowstr, k, m = nk.parse(flowstr, field[2]) 1703918423fdSAaron Conole else: 1704918423fdSAaron Conole flowstr = flowstr[len(fld) :] 1705918423fdSAaron Conole flowstr, k, m = field[2](flowstr) 1706918423fdSAaron Conole 1707918423fdSAaron Conole if m and mask is not None: 1708918423fdSAaron Conole mask["attrs"].append([field[0], m]) 1709918423fdSAaron Conole self["attrs"].append([field[0], k]) 1710918423fdSAaron Conole 1711918423fdSAaron Conole flowstr = flowstr[strspn(flowstr, "), ") :] 1712918423fdSAaron Conole 1713918423fdSAaron Conole return flowstr 1714918423fdSAaron Conole 1715e52b07aaSAaron Conole def dpstr(self, mask=None, more=False): 1716e52b07aaSAaron Conole print_str = "" 1717e52b07aaSAaron Conole 1718e52b07aaSAaron Conole for field in ( 1719e52b07aaSAaron Conole ( 1720e52b07aaSAaron Conole "OVS_KEY_ATTR_PRIORITY", 1721e52b07aaSAaron Conole "skb_priority", 1722e52b07aaSAaron Conole "%d", 1723e52b07aaSAaron Conole lambda x: False, 1724e52b07aaSAaron Conole True, 1725e52b07aaSAaron Conole ), 1726e52b07aaSAaron Conole ( 1727e52b07aaSAaron Conole "OVS_KEY_ATTR_SKB_MARK", 1728e52b07aaSAaron Conole "skb_mark", 1729e52b07aaSAaron Conole "%d", 1730e52b07aaSAaron Conole lambda x: False, 1731e52b07aaSAaron Conole True, 1732e52b07aaSAaron Conole ), 1733e52b07aaSAaron Conole ( 1734e52b07aaSAaron Conole "OVS_KEY_ATTR_RECIRC_ID", 1735e52b07aaSAaron Conole "recirc_id", 1736e52b07aaSAaron Conole "0x%08X", 1737e52b07aaSAaron Conole lambda x: False, 1738e52b07aaSAaron Conole True, 1739e52b07aaSAaron Conole ), 1740e52b07aaSAaron Conole ( 1741e52b07aaSAaron Conole "OVS_KEY_ATTR_DP_HASH", 1742e52b07aaSAaron Conole "dp_hash", 1743e52b07aaSAaron Conole "0x%08X", 1744e52b07aaSAaron Conole lambda x: False, 1745e52b07aaSAaron Conole True, 1746e52b07aaSAaron Conole ), 1747e52b07aaSAaron Conole ( 1748fefe3b7dSAaron Conole "OVS_KEY_ATTR_TUNNEL", 1749fefe3b7dSAaron Conole "tunnel", 1750fefe3b7dSAaron Conole None, 1751fefe3b7dSAaron Conole False, 1752fefe3b7dSAaron Conole False, 1753fefe3b7dSAaron Conole ), 1754fefe3b7dSAaron Conole ( 1755e52b07aaSAaron Conole "OVS_KEY_ATTR_CT_STATE", 1756e52b07aaSAaron Conole "ct_state", 1757e52b07aaSAaron Conole "0x%04x", 1758e52b07aaSAaron Conole lambda x: False, 1759e52b07aaSAaron Conole True, 1760e52b07aaSAaron Conole ), 1761e52b07aaSAaron Conole ( 1762e52b07aaSAaron Conole "OVS_KEY_ATTR_CT_ZONE", 1763e52b07aaSAaron Conole "ct_zone", 1764e52b07aaSAaron Conole "0x%04x", 1765e52b07aaSAaron Conole lambda x: False, 1766e52b07aaSAaron Conole True, 1767e52b07aaSAaron Conole ), 1768e52b07aaSAaron Conole ( 1769e52b07aaSAaron Conole "OVS_KEY_ATTR_CT_MARK", 1770e52b07aaSAaron Conole "ct_mark", 1771e52b07aaSAaron Conole "0x%08x", 1772e52b07aaSAaron Conole lambda x: False, 1773e52b07aaSAaron Conole True, 1774e52b07aaSAaron Conole ), 1775e52b07aaSAaron Conole ( 1776e52b07aaSAaron Conole "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", 1777e52b07aaSAaron Conole None, 1778e52b07aaSAaron Conole None, 1779e52b07aaSAaron Conole False, 1780e52b07aaSAaron Conole False, 1781e52b07aaSAaron Conole ), 1782e52b07aaSAaron Conole ( 1783e52b07aaSAaron Conole "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", 1784e52b07aaSAaron Conole None, 1785e52b07aaSAaron Conole None, 1786e52b07aaSAaron Conole False, 1787e52b07aaSAaron Conole False, 1788e52b07aaSAaron Conole ), 1789e52b07aaSAaron Conole ( 1790e52b07aaSAaron Conole "OVS_KEY_ATTR_IN_PORT", 1791e52b07aaSAaron Conole "in_port", 1792e52b07aaSAaron Conole "%d", 1793e52b07aaSAaron Conole lambda x: True, 1794e52b07aaSAaron Conole True, 1795e52b07aaSAaron Conole ), 1796e52b07aaSAaron Conole ("OVS_KEY_ATTR_ETHERNET", None, None, False, False), 1797e52b07aaSAaron Conole ( 1798e52b07aaSAaron Conole "OVS_KEY_ATTR_ETHERTYPE", 1799e52b07aaSAaron Conole "eth_type", 1800e52b07aaSAaron Conole "0x%04x", 1801e52b07aaSAaron Conole lambda x: int(x) == 0xFFFF, 1802e52b07aaSAaron Conole True, 1803e52b07aaSAaron Conole ), 1804e52b07aaSAaron Conole ("OVS_KEY_ATTR_IPV4", None, None, False, False), 1805e52b07aaSAaron Conole ("OVS_KEY_ATTR_IPV6", None, None, False, False), 1806e52b07aaSAaron Conole ("OVS_KEY_ATTR_ARP", None, None, False, False), 1807e52b07aaSAaron Conole ("OVS_KEY_ATTR_TCP", None, None, False, False), 1808e52b07aaSAaron Conole ( 1809e52b07aaSAaron Conole "OVS_KEY_ATTR_TCP_FLAGS", 1810e52b07aaSAaron Conole "tcp_flags", 1811e52b07aaSAaron Conole "0x%04x", 1812e52b07aaSAaron Conole lambda x: False, 1813e52b07aaSAaron Conole True, 1814e52b07aaSAaron Conole ), 1815e52b07aaSAaron Conole ("OVS_KEY_ATTR_UDP", None, None, False, False), 1816e52b07aaSAaron Conole ("OVS_KEY_ATTR_SCTP", None, None, False, False), 1817e52b07aaSAaron Conole ("OVS_KEY_ATTR_ICMP", None, None, False, False), 1818e52b07aaSAaron Conole ("OVS_KEY_ATTR_ICMPV6", None, None, False, False), 1819e52b07aaSAaron Conole ("OVS_KEY_ATTR_ND", None, None, False, False), 1820e52b07aaSAaron Conole ): 1821e52b07aaSAaron Conole v = self.get_attr(field[0]) 1822e52b07aaSAaron Conole if v is not None: 1823e52b07aaSAaron Conole m = None if mask is None else mask.get_attr(field[0]) 1824e52b07aaSAaron Conole if field[4] is False: 1825e52b07aaSAaron Conole print_str += v.dpstr(m, more) 1826e52b07aaSAaron Conole print_str += "," 1827e52b07aaSAaron Conole else: 1828e52b07aaSAaron Conole if m is None or field[3](m): 1829e52b07aaSAaron Conole print_str += field[1] + "(" 1830e52b07aaSAaron Conole print_str += field[2] % v 1831e52b07aaSAaron Conole print_str += ")," 1832e52b07aaSAaron Conole elif more or m != 0: 1833e52b07aaSAaron Conole print_str += field[1] + "(" 1834e52b07aaSAaron Conole print_str += (field[2] % v) + "/" + (field[2] % m) 1835e52b07aaSAaron Conole print_str += ")," 1836e52b07aaSAaron Conole 1837e52b07aaSAaron Conole return print_str 1838e52b07aaSAaron Conole 1839e52b07aaSAaron Conole 18409feac87bSAaron Conoleclass OvsPacket(GenericNetlinkSocket): 18419feac87bSAaron Conole OVS_PACKET_CMD_MISS = 1 # Flow table miss 18429feac87bSAaron Conole OVS_PACKET_CMD_ACTION = 2 # USERSPACE action 18439feac87bSAaron Conole OVS_PACKET_CMD_EXECUTE = 3 # Apply actions to packet 18449feac87bSAaron Conole 18459feac87bSAaron Conole class ovs_packet_msg(ovs_dp_msg): 18469feac87bSAaron Conole nla_map = ( 18479feac87bSAaron Conole ("OVS_PACKET_ATTR_UNSPEC", "none"), 18489feac87bSAaron Conole ("OVS_PACKET_ATTR_PACKET", "array(uint8)"), 18499feac87bSAaron Conole ("OVS_PACKET_ATTR_KEY", "ovskey"), 18509feac87bSAaron Conole ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"), 18519feac87bSAaron Conole ("OVS_PACKET_ATTR_USERDATA", "none"), 18529feac87bSAaron Conole ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"), 18539feac87bSAaron Conole ("OVS_PACKET_ATTR_UNUSED1", "none"), 18549feac87bSAaron Conole ("OVS_PACKET_ATTR_UNUSED2", "none"), 18559feac87bSAaron Conole ("OVS_PACKET_ATTR_PROBE", "none"), 18569feac87bSAaron Conole ("OVS_PACKET_ATTR_MRU", "uint16"), 18579feac87bSAaron Conole ("OVS_PACKET_ATTR_LEN", "uint32"), 18589feac87bSAaron Conole ("OVS_PACKET_ATTR_HASH", "uint64"), 18599feac87bSAaron Conole ) 18609feac87bSAaron Conole 18619feac87bSAaron Conole def __init__(self): 18629feac87bSAaron Conole GenericNetlinkSocket.__init__(self) 18639feac87bSAaron Conole self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg) 18649feac87bSAaron Conole 18659feac87bSAaron Conole def upcall_handler(self, up=None): 18669feac87bSAaron Conole print("listening on upcall packet handler:", self.epid) 18679feac87bSAaron Conole while True: 18689feac87bSAaron Conole try: 18699feac87bSAaron Conole msgs = self.get() 18709feac87bSAaron Conole for msg in msgs: 18719feac87bSAaron Conole if not up: 18729feac87bSAaron Conole continue 18739feac87bSAaron Conole if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS: 18749feac87bSAaron Conole up.miss(msg) 18759feac87bSAaron Conole elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION: 18769feac87bSAaron Conole up.action(msg) 18779feac87bSAaron Conole elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE: 18789feac87bSAaron Conole up.execute(msg) 18799feac87bSAaron Conole else: 18809feac87bSAaron Conole print("Unkonwn cmd: %d" % msg["cmd"]) 18819feac87bSAaron Conole except NetlinkError as ne: 18829feac87bSAaron Conole raise ne 18839feac87bSAaron Conole 18849feac87bSAaron Conole 188525f16c87SAaron Conoleclass OvsDatapath(GenericNetlinkSocket): 188625f16c87SAaron Conole OVS_DP_F_VPORT_PIDS = 1 << 1 188725f16c87SAaron Conole OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3 188825f16c87SAaron Conole 188925f16c87SAaron Conole class dp_cmd_msg(ovs_dp_msg): 189025f16c87SAaron Conole """ 189125f16c87SAaron Conole Message class that will be used to communicate with the kernel module. 189225f16c87SAaron Conole """ 189325f16c87SAaron Conole 189425f16c87SAaron Conole nla_map = ( 189525f16c87SAaron Conole ("OVS_DP_ATTR_UNSPEC", "none"), 189625f16c87SAaron Conole ("OVS_DP_ATTR_NAME", "asciiz"), 1897306dc213SAaron Conole ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"), 189825f16c87SAaron Conole ("OVS_DP_ATTR_STATS", "dpstats"), 189925f16c87SAaron Conole ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"), 190025f16c87SAaron Conole ("OVS_DP_ATTR_USER_FEATURES", "uint32"), 190125f16c87SAaron Conole ("OVS_DP_ATTR_PAD", "none"), 190225f16c87SAaron Conole ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"), 190325f16c87SAaron Conole ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"), 190425f16c87SAaron Conole ) 190525f16c87SAaron Conole 190625f16c87SAaron Conole class dpstats(nla): 190725f16c87SAaron Conole fields = ( 190825f16c87SAaron Conole ("hit", "=Q"), 190925f16c87SAaron Conole ("missed", "=Q"), 191025f16c87SAaron Conole ("lost", "=Q"), 191125f16c87SAaron Conole ("flows", "=Q"), 191225f16c87SAaron Conole ) 191325f16c87SAaron Conole 191425f16c87SAaron Conole class megaflowstats(nla): 191525f16c87SAaron Conole fields = ( 191625f16c87SAaron Conole ("mask_hit", "=Q"), 191725f16c87SAaron Conole ("masks", "=I"), 191825f16c87SAaron Conole ("padding", "=I"), 191925f16c87SAaron Conole ("cache_hits", "=Q"), 192025f16c87SAaron Conole ("pad1", "=Q"), 192125f16c87SAaron Conole ) 192225f16c87SAaron Conole 192325f16c87SAaron Conole def __init__(self): 192425f16c87SAaron Conole GenericNetlinkSocket.__init__(self) 192525f16c87SAaron Conole self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg) 192625f16c87SAaron Conole 192725f16c87SAaron Conole def info(self, dpname, ifindex=0): 192825f16c87SAaron Conole msg = OvsDatapath.dp_cmd_msg() 192925f16c87SAaron Conole msg["cmd"] = OVS_DP_CMD_GET 193025f16c87SAaron Conole msg["version"] = OVS_DATAPATH_VERSION 193125f16c87SAaron Conole msg["reserved"] = 0 193225f16c87SAaron Conole msg["dpifindex"] = ifindex 193325f16c87SAaron Conole msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 193425f16c87SAaron Conole 193525f16c87SAaron Conole try: 193625f16c87SAaron Conole reply = self.nlm_request( 193725f16c87SAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST 193825f16c87SAaron Conole ) 193925f16c87SAaron Conole reply = reply[0] 194025f16c87SAaron Conole except NetlinkError as ne: 194125f16c87SAaron Conole if ne.code == errno.ENODEV: 194225f16c87SAaron Conole reply = None 194325f16c87SAaron Conole else: 194425f16c87SAaron Conole raise ne 194525f16c87SAaron Conole 194625f16c87SAaron Conole return reply 194725f16c87SAaron Conole 19489feac87bSAaron Conole def create( 19499feac87bSAaron Conole self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket() 19509feac87bSAaron Conole ): 195125f16c87SAaron Conole msg = OvsDatapath.dp_cmd_msg() 195225f16c87SAaron Conole msg["cmd"] = OVS_DP_CMD_NEW 195325f16c87SAaron Conole if versionStr is None: 195425f16c87SAaron Conole msg["version"] = OVS_DATAPATH_VERSION 195525f16c87SAaron Conole else: 195625f16c87SAaron Conole msg["version"] = int(versionStr.split(":")[0], 0) 195725f16c87SAaron Conole msg["reserved"] = 0 195825f16c87SAaron Conole msg["dpifindex"] = 0 195925f16c87SAaron Conole msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 196025f16c87SAaron Conole 196125f16c87SAaron Conole dpfeatures = 0 196225f16c87SAaron Conole if versionStr is not None and versionStr.find(":") != -1: 196325f16c87SAaron Conole dpfeatures = int(versionStr.split(":")[1], 0) 196425f16c87SAaron Conole else: 19659feac87bSAaron Conole if versionStr is None or versionStr.find(":") == -1: 19669feac87bSAaron Conole dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU 19679feac87bSAaron Conole dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS 196825f16c87SAaron Conole 19699feac87bSAaron Conole nproc = multiprocessing.cpu_count() 19709feac87bSAaron Conole procarray = [] 19719feac87bSAaron Conole for i in range(1, nproc): 19729feac87bSAaron Conole procarray += [int(p.epid)] 19739feac87bSAaron Conole msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray]) 197425f16c87SAaron Conole msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures]) 197525f16c87SAaron Conole if not shouldUpcall: 19769feac87bSAaron Conole msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]]) 197725f16c87SAaron Conole 197825f16c87SAaron Conole try: 197925f16c87SAaron Conole reply = self.nlm_request( 198025f16c87SAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 198125f16c87SAaron Conole ) 198225f16c87SAaron Conole reply = reply[0] 198325f16c87SAaron Conole except NetlinkError as ne: 198425f16c87SAaron Conole if ne.code == errno.EEXIST: 198525f16c87SAaron Conole reply = None 198625f16c87SAaron Conole else: 198725f16c87SAaron Conole raise ne 198825f16c87SAaron Conole 198925f16c87SAaron Conole return reply 199025f16c87SAaron Conole 199125f16c87SAaron Conole def destroy(self, dpname): 199225f16c87SAaron Conole msg = OvsDatapath.dp_cmd_msg() 199325f16c87SAaron Conole msg["cmd"] = OVS_DP_CMD_DEL 199425f16c87SAaron Conole msg["version"] = OVS_DATAPATH_VERSION 199525f16c87SAaron Conole msg["reserved"] = 0 199625f16c87SAaron Conole msg["dpifindex"] = 0 199725f16c87SAaron Conole msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname]) 199825f16c87SAaron Conole 199925f16c87SAaron Conole try: 200025f16c87SAaron Conole reply = self.nlm_request( 200125f16c87SAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 200225f16c87SAaron Conole ) 200325f16c87SAaron Conole reply = reply[0] 200425f16c87SAaron Conole except NetlinkError as ne: 200525f16c87SAaron Conole if ne.code == errno.ENODEV: 200625f16c87SAaron Conole reply = None 200725f16c87SAaron Conole else: 200825f16c87SAaron Conole raise ne 200925f16c87SAaron Conole 201025f16c87SAaron Conole return reply 201125f16c87SAaron Conole 201225f16c87SAaron Conole 201325f16c87SAaron Conoleclass OvsVport(GenericNetlinkSocket): 201474cc26f4SAaron Conole OVS_VPORT_TYPE_NETDEV = 1 201574cc26f4SAaron Conole OVS_VPORT_TYPE_INTERNAL = 2 201674cc26f4SAaron Conole OVS_VPORT_TYPE_GRE = 3 201774cc26f4SAaron Conole OVS_VPORT_TYPE_VXLAN = 4 201874cc26f4SAaron Conole OVS_VPORT_TYPE_GENEVE = 5 201974cc26f4SAaron Conole 202025f16c87SAaron Conole class ovs_vport_msg(ovs_dp_msg): 202125f16c87SAaron Conole nla_map = ( 202225f16c87SAaron Conole ("OVS_VPORT_ATTR_UNSPEC", "none"), 202325f16c87SAaron Conole ("OVS_VPORT_ATTR_PORT_NO", "uint32"), 202425f16c87SAaron Conole ("OVS_VPORT_ATTR_TYPE", "uint32"), 202525f16c87SAaron Conole ("OVS_VPORT_ATTR_NAME", "asciiz"), 2026f94ecbc9SAaron Conole ("OVS_VPORT_ATTR_OPTIONS", "vportopts"), 202725f16c87SAaron Conole ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"), 202825f16c87SAaron Conole ("OVS_VPORT_ATTR_STATS", "vportstats"), 202925f16c87SAaron Conole ("OVS_VPORT_ATTR_PAD", "none"), 203025f16c87SAaron Conole ("OVS_VPORT_ATTR_IFINDEX", "uint32"), 203125f16c87SAaron Conole ("OVS_VPORT_ATTR_NETNSID", "uint32"), 203225f16c87SAaron Conole ) 203325f16c87SAaron Conole 2034f94ecbc9SAaron Conole class vportopts(nla): 2035f94ecbc9SAaron Conole nla_map = ( 2036f94ecbc9SAaron Conole ("OVS_TUNNEL_ATTR_UNSPEC", "none"), 2037f94ecbc9SAaron Conole ("OVS_TUNNEL_ATTR_DST_PORT", "uint16"), 2038f94ecbc9SAaron Conole ("OVS_TUNNEL_ATTR_EXTENSION", "none"), 2039f94ecbc9SAaron Conole ) 2040f94ecbc9SAaron Conole 204125f16c87SAaron Conole class vportstats(nla): 204225f16c87SAaron Conole fields = ( 204325f16c87SAaron Conole ("rx_packets", "=Q"), 204425f16c87SAaron Conole ("tx_packets", "=Q"), 204525f16c87SAaron Conole ("rx_bytes", "=Q"), 204625f16c87SAaron Conole ("tx_bytes", "=Q"), 204725f16c87SAaron Conole ("rx_errors", "=Q"), 204825f16c87SAaron Conole ("tx_errors", "=Q"), 204925f16c87SAaron Conole ("rx_dropped", "=Q"), 205025f16c87SAaron Conole ("tx_dropped", "=Q"), 205125f16c87SAaron Conole ) 205225f16c87SAaron Conole 205325f16c87SAaron Conole def type_to_str(vport_type): 205474cc26f4SAaron Conole if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV: 205525f16c87SAaron Conole return "netdev" 205674cc26f4SAaron Conole elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL: 205725f16c87SAaron Conole return "internal" 205874cc26f4SAaron Conole elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE: 205925f16c87SAaron Conole return "gre" 206074cc26f4SAaron Conole elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN: 206125f16c87SAaron Conole return "vxlan" 206274cc26f4SAaron Conole elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE: 206325f16c87SAaron Conole return "geneve" 206474cc26f4SAaron Conole raise ValueError("Unknown vport type:%d" % vport_type) 206574cc26f4SAaron Conole 206674cc26f4SAaron Conole def str_to_type(vport_type): 206774cc26f4SAaron Conole if vport_type == "netdev": 206874cc26f4SAaron Conole return OvsVport.OVS_VPORT_TYPE_NETDEV 206974cc26f4SAaron Conole elif vport_type == "internal": 207074cc26f4SAaron Conole return OvsVport.OVS_VPORT_TYPE_INTERNAL 207174cc26f4SAaron Conole elif vport_type == "gre": 207274cc26f4SAaron Conole return OvsVport.OVS_VPORT_TYPE_INTERNAL 207374cc26f4SAaron Conole elif vport_type == "vxlan": 207474cc26f4SAaron Conole return OvsVport.OVS_VPORT_TYPE_VXLAN 207574cc26f4SAaron Conole elif vport_type == "geneve": 207674cc26f4SAaron Conole return OvsVport.OVS_VPORT_TYPE_GENEVE 207774cc26f4SAaron Conole raise ValueError("Unknown vport type: '%s'" % vport_type) 207825f16c87SAaron Conole 20799feac87bSAaron Conole def __init__(self, packet=OvsPacket()): 208025f16c87SAaron Conole GenericNetlinkSocket.__init__(self) 208125f16c87SAaron Conole self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg) 20829feac87bSAaron Conole self.upcall_packet = packet 208325f16c87SAaron Conole 208425f16c87SAaron Conole def info(self, vport_name, dpifindex=0, portno=None): 208525f16c87SAaron Conole msg = OvsVport.ovs_vport_msg() 208625f16c87SAaron Conole 208725f16c87SAaron Conole msg["cmd"] = OVS_VPORT_CMD_GET 208825f16c87SAaron Conole msg["version"] = OVS_DATAPATH_VERSION 208925f16c87SAaron Conole msg["reserved"] = 0 209025f16c87SAaron Conole msg["dpifindex"] = dpifindex 209125f16c87SAaron Conole 209225f16c87SAaron Conole if portno is None: 209325f16c87SAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name]) 209425f16c87SAaron Conole else: 209525f16c87SAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno]) 209625f16c87SAaron Conole 209725f16c87SAaron Conole try: 209825f16c87SAaron Conole reply = self.nlm_request( 209925f16c87SAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST 210025f16c87SAaron Conole ) 210125f16c87SAaron Conole reply = reply[0] 210225f16c87SAaron Conole except NetlinkError as ne: 210325f16c87SAaron Conole if ne.code == errno.ENODEV: 210425f16c87SAaron Conole reply = None 210525f16c87SAaron Conole else: 210625f16c87SAaron Conole raise ne 210725f16c87SAaron Conole return reply 210825f16c87SAaron Conole 2109f94ecbc9SAaron Conole def attach(self, dpindex, vport_ifname, ptype, dport, lwt): 211074cc26f4SAaron Conole msg = OvsVport.ovs_vport_msg() 211125f16c87SAaron Conole 211274cc26f4SAaron Conole msg["cmd"] = OVS_VPORT_CMD_NEW 211374cc26f4SAaron Conole msg["version"] = OVS_DATAPATH_VERSION 211474cc26f4SAaron Conole msg["reserved"] = 0 211574cc26f4SAaron Conole msg["dpifindex"] = dpindex 211674cc26f4SAaron Conole port_type = OvsVport.str_to_type(ptype) 211774cc26f4SAaron Conole 211874cc26f4SAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 21199feac87bSAaron Conole msg["attrs"].append( 21209feac87bSAaron Conole ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]] 21219feac87bSAaron Conole ) 21229feac87bSAaron Conole 2123f94ecbc9SAaron Conole TUNNEL_DEFAULTS = [("geneve", 6081), 2124f94ecbc9SAaron Conole ("vxlan", 4789)] 2125f94ecbc9SAaron Conole 2126f94ecbc9SAaron Conole for tnl in TUNNEL_DEFAULTS: 2127f94ecbc9SAaron Conole if ptype == tnl[0]: 2128f94ecbc9SAaron Conole if not dport: 2129f94ecbc9SAaron Conole dport = tnl[1] 2130f94ecbc9SAaron Conole 2131f94ecbc9SAaron Conole if not lwt: 2132f94ecbc9SAaron Conole vportopt = OvsVport.ovs_vport_msg.vportopts() 2133f94ecbc9SAaron Conole vportopt["attrs"].append( 2134f94ecbc9SAaron Conole ["OVS_TUNNEL_ATTR_DST_PORT", socket.htons(dport)] 2135f94ecbc9SAaron Conole ) 2136f94ecbc9SAaron Conole msg["attrs"].append( 2137f94ecbc9SAaron Conole ["OVS_VPORT_ATTR_OPTIONS", vportopt] 2138f94ecbc9SAaron Conole ) 2139f94ecbc9SAaron Conole else: 2140f94ecbc9SAaron Conole port_type = OvsVport.OVS_VPORT_TYPE_NETDEV 2141f94ecbc9SAaron Conole ipr = pyroute2.iproute.IPRoute() 2142f94ecbc9SAaron Conole 2143f94ecbc9SAaron Conole if tnl[0] == "geneve": 2144f94ecbc9SAaron Conole ipr.link("add", ifname=vport_ifname, kind=tnl[0], 2145f94ecbc9SAaron Conole geneve_port=dport, 2146f94ecbc9SAaron Conole geneve_collect_metadata=True, 2147f94ecbc9SAaron Conole geneve_udp_zero_csum6_rx=1) 2148f94ecbc9SAaron Conole elif tnl[0] == "vxlan": 2149f94ecbc9SAaron Conole ipr.link("add", ifname=vport_ifname, kind=tnl[0], 2150f94ecbc9SAaron Conole vxlan_learning=0, vxlan_collect_metadata=1, 2151f94ecbc9SAaron Conole vxlan_udp_zero_csum6_rx=1, vxlan_port=dport) 2152f94ecbc9SAaron Conole break 2153f94ecbc9SAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type]) 2154f94ecbc9SAaron Conole 21559feac87bSAaron Conole try: 21569feac87bSAaron Conole reply = self.nlm_request( 21579feac87bSAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 21589feac87bSAaron Conole ) 21599feac87bSAaron Conole reply = reply[0] 21609feac87bSAaron Conole except NetlinkError as ne: 21619feac87bSAaron Conole if ne.code == errno.EEXIST: 21629feac87bSAaron Conole reply = None 21639feac87bSAaron Conole else: 21649feac87bSAaron Conole raise ne 21659feac87bSAaron Conole return reply 21669feac87bSAaron Conole 21679feac87bSAaron Conole def reset_upcall(self, dpindex, vport_ifname, p=None): 21689feac87bSAaron Conole msg = OvsVport.ovs_vport_msg() 21699feac87bSAaron Conole 21709feac87bSAaron Conole msg["cmd"] = OVS_VPORT_CMD_SET 21719feac87bSAaron Conole msg["version"] = OVS_DATAPATH_VERSION 21729feac87bSAaron Conole msg["reserved"] = 0 21739feac87bSAaron Conole msg["dpifindex"] = dpindex 21749feac87bSAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 21759feac87bSAaron Conole 21769feac87bSAaron Conole if p == None: 21779feac87bSAaron Conole p = self.upcall_packet 21789feac87bSAaron Conole else: 21799feac87bSAaron Conole self.upcall_packet = p 21809feac87bSAaron Conole 21819feac87bSAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]]) 218274cc26f4SAaron Conole 218374cc26f4SAaron Conole try: 218474cc26f4SAaron Conole reply = self.nlm_request( 218574cc26f4SAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 218674cc26f4SAaron Conole ) 218774cc26f4SAaron Conole reply = reply[0] 218874cc26f4SAaron Conole except NetlinkError as ne: 218974cc26f4SAaron Conole raise ne 219074cc26f4SAaron Conole return reply 219174cc26f4SAaron Conole 219274cc26f4SAaron Conole def detach(self, dpindex, vport_ifname): 219374cc26f4SAaron Conole msg = OvsVport.ovs_vport_msg() 219474cc26f4SAaron Conole 219574cc26f4SAaron Conole msg["cmd"] = OVS_VPORT_CMD_DEL 219674cc26f4SAaron Conole msg["version"] = OVS_DATAPATH_VERSION 219774cc26f4SAaron Conole msg["reserved"] = 0 219874cc26f4SAaron Conole msg["dpifindex"] = dpindex 219974cc26f4SAaron Conole msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname]) 220074cc26f4SAaron Conole 220174cc26f4SAaron Conole try: 220274cc26f4SAaron Conole reply = self.nlm_request( 220374cc26f4SAaron Conole msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK 220474cc26f4SAaron Conole ) 220574cc26f4SAaron Conole reply = reply[0] 220674cc26f4SAaron Conole except NetlinkError as ne: 220774cc26f4SAaron Conole if ne.code == errno.ENODEV: 220874cc26f4SAaron Conole reply = None 220974cc26f4SAaron Conole else: 221074cc26f4SAaron Conole raise ne 221174cc26f4SAaron Conole return reply 221274cc26f4SAaron Conole 22139feac87bSAaron Conole def upcall_handler(self, handler=None): 22149feac87bSAaron Conole self.upcall_packet.upcall_handler(handler) 22159feac87bSAaron Conole 221674cc26f4SAaron Conole 2217e52b07aaSAaron Conoleclass OvsFlow(GenericNetlinkSocket): 2218e52b07aaSAaron Conole class ovs_flow_msg(ovs_dp_msg): 2219e52b07aaSAaron Conole nla_map = ( 2220e52b07aaSAaron Conole ("OVS_FLOW_ATTR_UNSPEC", "none"), 2221e52b07aaSAaron Conole ("OVS_FLOW_ATTR_KEY", "ovskey"), 2222e52b07aaSAaron Conole ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"), 2223e52b07aaSAaron Conole ("OVS_FLOW_ATTR_STATS", "flowstats"), 2224e52b07aaSAaron Conole ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"), 2225e52b07aaSAaron Conole ("OVS_FLOW_ATTR_USED", "uint64"), 2226e52b07aaSAaron Conole ("OVS_FLOW_ATTR_CLEAR", "none"), 2227e52b07aaSAaron Conole ("OVS_FLOW_ATTR_MASK", "ovskey"), 2228e52b07aaSAaron Conole ("OVS_FLOW_ATTR_PROBE", "none"), 2229e52b07aaSAaron Conole ("OVS_FLOW_ATTR_UFID", "array(uint32)"), 2230e52b07aaSAaron Conole ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"), 2231e52b07aaSAaron Conole ) 2232e52b07aaSAaron Conole 2233e52b07aaSAaron Conole class flowstats(nla): 2234e52b07aaSAaron Conole fields = ( 2235e52b07aaSAaron Conole ("packets", "=Q"), 2236e52b07aaSAaron Conole ("bytes", "=Q"), 2237e52b07aaSAaron Conole ) 2238e52b07aaSAaron Conole 2239e52b07aaSAaron Conole def dpstr(self, more=False): 2240e52b07aaSAaron Conole ufid = self.get_attr("OVS_FLOW_ATTR_UFID") 2241e52b07aaSAaron Conole ufid_str = "" 2242e52b07aaSAaron Conole if ufid is not None: 2243e52b07aaSAaron Conole ufid_str = ( 2244e52b07aaSAaron Conole "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format( 2245e52b07aaSAaron Conole ufid[0], 2246e52b07aaSAaron Conole ufid[1] >> 16, 2247e52b07aaSAaron Conole ufid[1] & 0xFFFF, 2248e52b07aaSAaron Conole ufid[2] >> 16, 2249e52b07aaSAaron Conole ufid[2] & 0, 2250e52b07aaSAaron Conole ufid[3], 2251e52b07aaSAaron Conole ) 2252e52b07aaSAaron Conole ) 2253e52b07aaSAaron Conole 2254e52b07aaSAaron Conole key_field = self.get_attr("OVS_FLOW_ATTR_KEY") 2255e52b07aaSAaron Conole keymsg = None 2256e52b07aaSAaron Conole if key_field is not None: 2257e52b07aaSAaron Conole keymsg = key_field 2258e52b07aaSAaron Conole 2259e52b07aaSAaron Conole mask_field = self.get_attr("OVS_FLOW_ATTR_MASK") 2260e52b07aaSAaron Conole maskmsg = None 2261e52b07aaSAaron Conole if mask_field is not None: 2262e52b07aaSAaron Conole maskmsg = mask_field 2263e52b07aaSAaron Conole 2264e52b07aaSAaron Conole acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS") 2265e52b07aaSAaron Conole actsmsg = None 2266e52b07aaSAaron Conole if acts_field is not None: 2267e52b07aaSAaron Conole actsmsg = acts_field 2268e52b07aaSAaron Conole 2269e52b07aaSAaron Conole print_str = "" 2270e52b07aaSAaron Conole 2271e52b07aaSAaron Conole if more: 2272e52b07aaSAaron Conole print_str += ufid_str + "," 2273e52b07aaSAaron Conole 2274e52b07aaSAaron Conole if keymsg is not None: 2275e52b07aaSAaron Conole print_str += keymsg.dpstr(maskmsg, more) 2276e52b07aaSAaron Conole 2277e52b07aaSAaron Conole stats = self.get_attr("OVS_FLOW_ATTR_STATS") 2278e52b07aaSAaron Conole if stats is None: 2279e52b07aaSAaron Conole print_str += " packets:0, bytes:0," 2280e52b07aaSAaron Conole else: 2281e52b07aaSAaron Conole print_str += " packets:%d, bytes:%d," % ( 2282e52b07aaSAaron Conole stats["packets"], 2283e52b07aaSAaron Conole stats["bytes"], 2284e52b07aaSAaron Conole ) 2285e52b07aaSAaron Conole 2286e52b07aaSAaron Conole used = self.get_attr("OVS_FLOW_ATTR_USED") 2287e52b07aaSAaron Conole print_str += " used:" 2288e52b07aaSAaron Conole if used is None: 2289e52b07aaSAaron Conole print_str += "never," 2290e52b07aaSAaron Conole else: 2291e52b07aaSAaron Conole used_time = int(used) 2292e52b07aaSAaron Conole cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC) 2293e52b07aaSAaron Conole used_time = (cur_time_sec * 1000) - used_time 2294e52b07aaSAaron Conole print_str += "{}s,".format(used_time / 1000) 2295e52b07aaSAaron Conole 2296e52b07aaSAaron Conole print_str += " actions:" 2297e52b07aaSAaron Conole if ( 2298e52b07aaSAaron Conole actsmsg is None 2299e52b07aaSAaron Conole or "attrs" not in actsmsg 2300e52b07aaSAaron Conole or len(actsmsg["attrs"]) == 0 2301e52b07aaSAaron Conole ): 2302e52b07aaSAaron Conole print_str += "drop" 2303e52b07aaSAaron Conole else: 2304e52b07aaSAaron Conole print_str += actsmsg.dpstr(more) 2305e52b07aaSAaron Conole 2306e52b07aaSAaron Conole return print_str 2307e52b07aaSAaron Conole 2308918423fdSAaron Conole def parse(self, flowstr, actstr, dpidx=0): 2309918423fdSAaron Conole OVS_UFID_F_OMIT_KEY = 1 << 0 2310918423fdSAaron Conole OVS_UFID_F_OMIT_MASK = 1 << 1 2311918423fdSAaron Conole OVS_UFID_F_OMIT_ACTIONS = 1 << 2 2312918423fdSAaron Conole 2313918423fdSAaron Conole self["cmd"] = 0 2314918423fdSAaron Conole self["version"] = 0 2315918423fdSAaron Conole self["reserved"] = 0 2316918423fdSAaron Conole self["dpifindex"] = 0 2317918423fdSAaron Conole 2318918423fdSAaron Conole if flowstr.startswith("ufid:"): 2319918423fdSAaron Conole count = 5 2320918423fdSAaron Conole while flowstr[count] != ",": 2321918423fdSAaron Conole count += 1 2322918423fdSAaron Conole ufidstr = flowstr[5:count] 2323918423fdSAaron Conole flowstr = flowstr[count + 1 :] 2324918423fdSAaron Conole else: 2325918423fdSAaron Conole ufidstr = str(uuid.uuid4()) 2326918423fdSAaron Conole uuidRawObj = uuid.UUID(ufidstr).fields 2327918423fdSAaron Conole 2328918423fdSAaron Conole self["attrs"].append( 2329918423fdSAaron Conole [ 2330918423fdSAaron Conole "OVS_FLOW_ATTR_UFID", 2331918423fdSAaron Conole [ 2332918423fdSAaron Conole uuidRawObj[0], 2333918423fdSAaron Conole uuidRawObj[1] << 16 | uuidRawObj[2], 2334918423fdSAaron Conole uuidRawObj[3] << 24 2335918423fdSAaron Conole | uuidRawObj[4] << 16 2336918423fdSAaron Conole | uuidRawObj[5] & (0xFF << 32) >> 32, 2337918423fdSAaron Conole uuidRawObj[5] & (0xFFFFFFFF), 2338918423fdSAaron Conole ], 2339918423fdSAaron Conole ] 2340918423fdSAaron Conole ) 2341918423fdSAaron Conole self["attrs"].append( 2342918423fdSAaron Conole [ 2343918423fdSAaron Conole "OVS_FLOW_ATTR_UFID_FLAGS", 2344918423fdSAaron Conole int( 2345918423fdSAaron Conole OVS_UFID_F_OMIT_KEY 2346918423fdSAaron Conole | OVS_UFID_F_OMIT_MASK 2347918423fdSAaron Conole | OVS_UFID_F_OMIT_ACTIONS 2348918423fdSAaron Conole ), 2349918423fdSAaron Conole ] 2350918423fdSAaron Conole ) 2351918423fdSAaron Conole 2352918423fdSAaron Conole k = ovskey() 2353918423fdSAaron Conole m = ovskey() 2354918423fdSAaron Conole k.parse(flowstr, m) 2355918423fdSAaron Conole self["attrs"].append(["OVS_FLOW_ATTR_KEY", k]) 2356918423fdSAaron Conole self["attrs"].append(["OVS_FLOW_ATTR_MASK", m]) 2357918423fdSAaron Conole 2358918423fdSAaron Conole a = ovsactions() 2359918423fdSAaron Conole a.parse(actstr) 2360918423fdSAaron Conole self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a]) 2361918423fdSAaron Conole 2362e52b07aaSAaron Conole def __init__(self): 2363e52b07aaSAaron Conole GenericNetlinkSocket.__init__(self) 2364e52b07aaSAaron Conole 2365e52b07aaSAaron Conole self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg) 2366e52b07aaSAaron Conole 2367918423fdSAaron Conole def add_flow(self, dpifindex, flowmsg): 2368918423fdSAaron Conole """ 2369918423fdSAaron Conole Send a new flow message to the kernel. 2370918423fdSAaron Conole 2371918423fdSAaron Conole dpifindex should be a valid datapath obtained by calling 2372918423fdSAaron Conole into the OvsDatapath lookup 2373918423fdSAaron Conole 2374918423fdSAaron Conole flowmsg is a flow object obtained by calling a dpparse 2375918423fdSAaron Conole """ 2376918423fdSAaron Conole 2377918423fdSAaron Conole flowmsg["cmd"] = OVS_FLOW_CMD_NEW 2378918423fdSAaron Conole flowmsg["version"] = OVS_DATAPATH_VERSION 2379918423fdSAaron Conole flowmsg["reserved"] = 0 2380918423fdSAaron Conole flowmsg["dpifindex"] = dpifindex 2381918423fdSAaron Conole 2382918423fdSAaron Conole try: 2383918423fdSAaron Conole reply = self.nlm_request( 2384918423fdSAaron Conole flowmsg, 2385918423fdSAaron Conole msg_type=self.prid, 2386918423fdSAaron Conole msg_flags=NLM_F_REQUEST | NLM_F_ACK, 2387918423fdSAaron Conole ) 2388918423fdSAaron Conole reply = reply[0] 2389918423fdSAaron Conole except NetlinkError as ne: 2390918423fdSAaron Conole print(flowmsg) 2391918423fdSAaron Conole raise ne 2392918423fdSAaron Conole return reply 2393918423fdSAaron Conole 239476035fd1SAaron Conole def del_flows(self, dpifindex): 239576035fd1SAaron Conole """ 239676035fd1SAaron Conole Send a del message to the kernel that will drop all flows. 239776035fd1SAaron Conole 239876035fd1SAaron Conole dpifindex should be a valid datapath obtained by calling 239976035fd1SAaron Conole into the OvsDatapath lookup 240076035fd1SAaron Conole """ 240176035fd1SAaron Conole 240276035fd1SAaron Conole flowmsg = OvsFlow.ovs_flow_msg() 240376035fd1SAaron Conole flowmsg["cmd"] = OVS_FLOW_CMD_DEL 240476035fd1SAaron Conole flowmsg["version"] = OVS_DATAPATH_VERSION 240576035fd1SAaron Conole flowmsg["reserved"] = 0 240676035fd1SAaron Conole flowmsg["dpifindex"] = dpifindex 240776035fd1SAaron Conole 240876035fd1SAaron Conole try: 240976035fd1SAaron Conole reply = self.nlm_request( 241076035fd1SAaron Conole flowmsg, 241176035fd1SAaron Conole msg_type=self.prid, 241276035fd1SAaron Conole msg_flags=NLM_F_REQUEST | NLM_F_ACK, 241376035fd1SAaron Conole ) 241476035fd1SAaron Conole reply = reply[0] 241576035fd1SAaron Conole except NetlinkError as ne: 241676035fd1SAaron Conole print(flowmsg) 241776035fd1SAaron Conole raise ne 241876035fd1SAaron Conole return reply 241976035fd1SAaron Conole 2420e52b07aaSAaron Conole def dump(self, dpifindex, flowspec=None): 2421e52b07aaSAaron Conole """ 2422e52b07aaSAaron Conole Returns a list of messages containing flows. 2423e52b07aaSAaron Conole 2424e52b07aaSAaron Conole dpifindex should be a valid datapath obtained by calling 2425e52b07aaSAaron Conole into the OvsDatapath lookup 2426e52b07aaSAaron Conole 2427e52b07aaSAaron Conole flowpsec is a string which represents a flow in the dpctl 2428e52b07aaSAaron Conole format. 2429e52b07aaSAaron Conole """ 2430e52b07aaSAaron Conole msg = OvsFlow.ovs_flow_msg() 2431e52b07aaSAaron Conole 2432e52b07aaSAaron Conole msg["cmd"] = OVS_FLOW_CMD_GET 2433e52b07aaSAaron Conole msg["version"] = OVS_DATAPATH_VERSION 2434e52b07aaSAaron Conole msg["reserved"] = 0 2435e52b07aaSAaron Conole msg["dpifindex"] = dpifindex 2436e52b07aaSAaron Conole 2437e52b07aaSAaron Conole msg_flags = NLM_F_REQUEST | NLM_F_ACK 2438e52b07aaSAaron Conole if flowspec is None: 2439e52b07aaSAaron Conole msg_flags |= NLM_F_DUMP 2440e52b07aaSAaron Conole rep = None 2441e52b07aaSAaron Conole 2442e52b07aaSAaron Conole try: 2443e52b07aaSAaron Conole rep = self.nlm_request( 2444e52b07aaSAaron Conole msg, 2445e52b07aaSAaron Conole msg_type=self.prid, 2446e52b07aaSAaron Conole msg_flags=msg_flags, 2447e52b07aaSAaron Conole ) 2448e52b07aaSAaron Conole except NetlinkError as ne: 2449e52b07aaSAaron Conole raise ne 2450e52b07aaSAaron Conole return rep 2451e52b07aaSAaron Conole 24529feac87bSAaron Conole def miss(self, packetmsg): 24539feac87bSAaron Conole seq = packetmsg["header"]["sequence_number"] 24549feac87bSAaron Conole keystr = "(none)" 24559feac87bSAaron Conole key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY") 24569feac87bSAaron Conole if key_field is not None: 24579feac87bSAaron Conole keystr = key_field.dpstr(None, True) 24589feac87bSAaron Conole 24599feac87bSAaron Conole pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET") 24609feac87bSAaron Conole pktpres = "yes" if pktdata is not None else "no" 24619feac87bSAaron Conole 24629feac87bSAaron Conole print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True) 24639feac87bSAaron Conole 24649feac87bSAaron Conole def execute(self, packetmsg): 246530d772a0SAdrian Moreno print("userspace execute command", flush=True) 24669feac87bSAaron Conole 24679feac87bSAaron Conole def action(self, packetmsg): 246830d772a0SAdrian Moreno print("userspace action command", flush=True) 246930d772a0SAdrian Moreno 247030d772a0SAdrian Moreno 247130d772a0SAdrian Morenoclass psample_sample(genlmsg): 247230d772a0SAdrian Moreno nla_map = ( 247330d772a0SAdrian Moreno ("PSAMPLE_ATTR_IIFINDEX", "none"), 247430d772a0SAdrian Moreno ("PSAMPLE_ATTR_OIFINDEX", "none"), 247530d772a0SAdrian Moreno ("PSAMPLE_ATTR_ORIGSIZE", "none"), 247630d772a0SAdrian Moreno ("PSAMPLE_ATTR_SAMPLE_GROUP", "uint32"), 247730d772a0SAdrian Moreno ("PSAMPLE_ATTR_GROUP_SEQ", "none"), 247830d772a0SAdrian Moreno ("PSAMPLE_ATTR_SAMPLE_RATE", "uint32"), 247930d772a0SAdrian Moreno ("PSAMPLE_ATTR_DATA", "array(uint8)"), 248030d772a0SAdrian Moreno ("PSAMPLE_ATTR_GROUP_REFCOUNT", "none"), 248130d772a0SAdrian Moreno ("PSAMPLE_ATTR_TUNNEL", "none"), 248230d772a0SAdrian Moreno ("PSAMPLE_ATTR_PAD", "none"), 248330d772a0SAdrian Moreno ("PSAMPLE_ATTR_OUT_TC", "none"), 248430d772a0SAdrian Moreno ("PSAMPLE_ATTR_OUT_TC_OCC", "none"), 248530d772a0SAdrian Moreno ("PSAMPLE_ATTR_LATENCY", "none"), 248630d772a0SAdrian Moreno ("PSAMPLE_ATTR_TIMESTAMP", "none"), 248730d772a0SAdrian Moreno ("PSAMPLE_ATTR_PROTO", "none"), 248830d772a0SAdrian Moreno ("PSAMPLE_ATTR_USER_COOKIE", "array(uint8)"), 248930d772a0SAdrian Moreno ) 249030d772a0SAdrian Moreno 249130d772a0SAdrian Moreno def dpstr(self): 249230d772a0SAdrian Moreno fields = [] 249330d772a0SAdrian Moreno data = "" 249430d772a0SAdrian Moreno for (attr, value) in self["attrs"]: 249530d772a0SAdrian Moreno if attr == "PSAMPLE_ATTR_SAMPLE_GROUP": 249630d772a0SAdrian Moreno fields.append("group:%d" % value) 249730d772a0SAdrian Moreno if attr == "PSAMPLE_ATTR_SAMPLE_RATE": 249830d772a0SAdrian Moreno fields.append("rate:%d" % value) 249930d772a0SAdrian Moreno if attr == "PSAMPLE_ATTR_USER_COOKIE": 250030d772a0SAdrian Moreno value = "".join(format(x, "02x") for x in value) 250130d772a0SAdrian Moreno fields.append("cookie:%s" % value) 250230d772a0SAdrian Moreno if attr == "PSAMPLE_ATTR_DATA" and len(value) > 0: 250330d772a0SAdrian Moreno data = "data:%s" % "".join(format(x, "02x") for x in value) 250430d772a0SAdrian Moreno 250530d772a0SAdrian Moreno return ("%s %s" % (",".join(fields), data)).strip() 250630d772a0SAdrian Moreno 250730d772a0SAdrian Moreno 250830d772a0SAdrian Morenoclass psample_msg(Marshal): 250930d772a0SAdrian Moreno PSAMPLE_CMD_SAMPLE = 0 251030d772a0SAdrian Moreno PSAMPLE_CMD_GET_GROUP = 1 251130d772a0SAdrian Moreno PSAMPLE_CMD_NEW_GROUP = 2 251230d772a0SAdrian Moreno PSAMPLE_CMD_DEL_GROUP = 3 251330d772a0SAdrian Moreno PSAMPLE_CMD_SET_FILTER = 4 251430d772a0SAdrian Moreno msg_map = {PSAMPLE_CMD_SAMPLE: psample_sample} 251530d772a0SAdrian Moreno 251630d772a0SAdrian Moreno 251730d772a0SAdrian Morenoclass PsampleEvent(EventSocket): 251830d772a0SAdrian Moreno genl_family = "psample" 251930d772a0SAdrian Moreno mcast_groups = ["packets"] 252030d772a0SAdrian Moreno marshal_class = psample_msg 252130d772a0SAdrian Moreno 252230d772a0SAdrian Moreno def read_samples(self): 2523*5e724cb6SAdrian Moreno print("listening for psample events", flush=True) 252430d772a0SAdrian Moreno while True: 252530d772a0SAdrian Moreno try: 252630d772a0SAdrian Moreno for msg in self.get(): 252730d772a0SAdrian Moreno print(msg.dpstr(), flush=True) 252830d772a0SAdrian Moreno except NetlinkError as ne: 252930d772a0SAdrian Moreno raise ne 25309feac87bSAaron Conole 2531e52b07aaSAaron Conole 253274cc26f4SAaron Conoledef print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()): 253325f16c87SAaron Conole dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME") 253425f16c87SAaron Conole base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS") 253525f16c87SAaron Conole megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS") 253625f16c87SAaron Conole user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES") 253725f16c87SAaron Conole masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE") 253825f16c87SAaron Conole 253925f16c87SAaron Conole print("%s:" % dp_name) 254025f16c87SAaron Conole print( 254125f16c87SAaron Conole " lookups: hit:%d missed:%d lost:%d" 254225f16c87SAaron Conole % (base_stats["hit"], base_stats["missed"], base_stats["lost"]) 254325f16c87SAaron Conole ) 254425f16c87SAaron Conole print(" flows:%d" % base_stats["flows"]) 254525f16c87SAaron Conole pkts = base_stats["hit"] + base_stats["missed"] 254625f16c87SAaron Conole avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0 254725f16c87SAaron Conole print( 254825f16c87SAaron Conole " masks: hit:%d total:%d hit/pkt:%f" 254925f16c87SAaron Conole % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg) 255025f16c87SAaron Conole ) 255125f16c87SAaron Conole print(" caches:") 255225f16c87SAaron Conole print(" masks-cache: size:%d" % masks_cache_size) 255325f16c87SAaron Conole 255425f16c87SAaron Conole if user_features is not None: 255525f16c87SAaron Conole print(" features: 0x%X" % user_features) 255625f16c87SAaron Conole 255725f16c87SAaron Conole # port print out 255825f16c87SAaron Conole for iface in ndb.interfaces: 255925f16c87SAaron Conole rep = vpl.info(iface.ifname, ifindex) 256025f16c87SAaron Conole if rep is not None: 2561f94ecbc9SAaron Conole opts = "" 2562f94ecbc9SAaron Conole vpo = rep.get_attr("OVS_VPORT_ATTR_OPTIONS") 2563f94ecbc9SAaron Conole if vpo: 2564f94ecbc9SAaron Conole dpo = vpo.get_attr("OVS_TUNNEL_ATTR_DST_PORT") 2565f94ecbc9SAaron Conole if dpo: 2566f94ecbc9SAaron Conole opts += " tnl-dport:%s" % socket.ntohs(dpo) 256725f16c87SAaron Conole print( 2568f94ecbc9SAaron Conole " port %d: %s (%s%s)" 256925f16c87SAaron Conole % ( 257025f16c87SAaron Conole rep.get_attr("OVS_VPORT_ATTR_PORT_NO"), 257125f16c87SAaron Conole rep.get_attr("OVS_VPORT_ATTR_NAME"), 257225f16c87SAaron Conole OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")), 2573f94ecbc9SAaron Conole opts, 257425f16c87SAaron Conole ) 257525f16c87SAaron Conole ) 257625f16c87SAaron Conole 257725f16c87SAaron Conole 257825f16c87SAaron Conoledef main(argv): 2579e52b07aaSAaron Conole nlmsg_atoms.ovskey = ovskey 2580e52b07aaSAaron Conole nlmsg_atoms.ovsactions = ovsactions 2581e52b07aaSAaron Conole 258292e37f20SAaron Conole # version check for pyroute2 258392e37f20SAaron Conole prverscheck = pyroute2.__version__.split(".") 258492e37f20SAaron Conole if int(prverscheck[0]) == 0 and int(prverscheck[1]) < 6: 258592e37f20SAaron Conole print("Need to upgrade the python pyroute2 package to >= 0.6.") 258692e37f20SAaron Conole sys.exit(0) 258792e37f20SAaron Conole 258825f16c87SAaron Conole parser = argparse.ArgumentParser() 258925f16c87SAaron Conole parser.add_argument( 259025f16c87SAaron Conole "-v", 259125f16c87SAaron Conole "--verbose", 259225f16c87SAaron Conole action="count", 259325f16c87SAaron Conole help="Increment 'verbose' output counter.", 2594e52b07aaSAaron Conole default=0, 259525f16c87SAaron Conole ) 259630d772a0SAdrian Moreno subparsers = parser.add_subparsers(dest="subcommand") 259725f16c87SAaron Conole 259825f16c87SAaron Conole showdpcmd = subparsers.add_parser("show") 259925f16c87SAaron Conole showdpcmd.add_argument( 260025f16c87SAaron Conole "showdp", metavar="N", type=str, nargs="?", help="Datapath Name" 260125f16c87SAaron Conole ) 260225f16c87SAaron Conole 260325f16c87SAaron Conole adddpcmd = subparsers.add_parser("add-dp") 260425f16c87SAaron Conole adddpcmd.add_argument("adddp", help="Datapath Name") 260525f16c87SAaron Conole adddpcmd.add_argument( 260625f16c87SAaron Conole "-u", 260725f16c87SAaron Conole "--upcall", 260825f16c87SAaron Conole action="store_true", 260925f16c87SAaron Conole help="Leave open a reader for upcalls", 261025f16c87SAaron Conole ) 261125f16c87SAaron Conole adddpcmd.add_argument( 261225f16c87SAaron Conole "-V", 261325f16c87SAaron Conole "--versioning", 261425f16c87SAaron Conole required=False, 261525f16c87SAaron Conole help="Specify a custom version / feature string", 261625f16c87SAaron Conole ) 261725f16c87SAaron Conole 261825f16c87SAaron Conole deldpcmd = subparsers.add_parser("del-dp") 261925f16c87SAaron Conole deldpcmd.add_argument("deldp", help="Datapath Name") 262025f16c87SAaron Conole 262174cc26f4SAaron Conole addifcmd = subparsers.add_parser("add-if") 262274cc26f4SAaron Conole addifcmd.add_argument("dpname", help="Datapath Name") 262374cc26f4SAaron Conole addifcmd.add_argument("addif", help="Interface name for adding") 262474cc26f4SAaron Conole addifcmd.add_argument( 26259feac87bSAaron Conole "-u", 26269feac87bSAaron Conole "--upcall", 26279feac87bSAaron Conole action="store_true", 26289feac87bSAaron Conole help="Leave open a reader for upcalls", 26299feac87bSAaron Conole ) 26309feac87bSAaron Conole addifcmd.add_argument( 263174cc26f4SAaron Conole "-t", 263274cc26f4SAaron Conole "--ptype", 263374cc26f4SAaron Conole type=str, 263474cc26f4SAaron Conole default="netdev", 2635f94ecbc9SAaron Conole choices=["netdev", "internal", "geneve", "vxlan"], 263674cc26f4SAaron Conole help="Interface type (default netdev)", 263774cc26f4SAaron Conole ) 2638f94ecbc9SAaron Conole addifcmd.add_argument( 2639f94ecbc9SAaron Conole "-p", 2640f94ecbc9SAaron Conole "--dport", 2641f94ecbc9SAaron Conole type=int, 2642f94ecbc9SAaron Conole default=0, 2643f94ecbc9SAaron Conole help="Destination port (0 for default)" 2644f94ecbc9SAaron Conole ) 2645f94ecbc9SAaron Conole addifcmd.add_argument( 2646f94ecbc9SAaron Conole "-l", 2647f94ecbc9SAaron Conole "--lwt", 2648f94ecbc9SAaron Conole type=bool, 2649f94ecbc9SAaron Conole default=True, 2650f94ecbc9SAaron Conole help="Use LWT infrastructure instead of vport (default true)." 2651f94ecbc9SAaron Conole ) 265274cc26f4SAaron Conole delifcmd = subparsers.add_parser("del-if") 265374cc26f4SAaron Conole delifcmd.add_argument("dpname", help="Datapath Name") 265474cc26f4SAaron Conole delifcmd.add_argument("delif", help="Interface name for adding") 2655f94ecbc9SAaron Conole delifcmd.add_argument("-d", 2656f94ecbc9SAaron Conole "--dellink", 2657f94ecbc9SAaron Conole type=bool, default=False, 2658f94ecbc9SAaron Conole help="Delete the link as well.") 265974cc26f4SAaron Conole 2660e52b07aaSAaron Conole dumpflcmd = subparsers.add_parser("dump-flows") 2661e52b07aaSAaron Conole dumpflcmd.add_argument("dumpdp", help="Datapath Name") 2662e52b07aaSAaron Conole 2663918423fdSAaron Conole addflcmd = subparsers.add_parser("add-flow") 2664918423fdSAaron Conole addflcmd.add_argument("flbr", help="Datapath name") 2665918423fdSAaron Conole addflcmd.add_argument("flow", help="Flow specification") 2666918423fdSAaron Conole addflcmd.add_argument("acts", help="Flow actions") 2667918423fdSAaron Conole 266876035fd1SAaron Conole delfscmd = subparsers.add_parser("del-flows") 266976035fd1SAaron Conole delfscmd.add_argument("flsbr", help="Datapath name") 267076035fd1SAaron Conole 267130d772a0SAdrian Moreno subparsers.add_parser("psample-events") 267230d772a0SAdrian Moreno 267325f16c87SAaron Conole args = parser.parse_args() 267425f16c87SAaron Conole 2675e52b07aaSAaron Conole if args.verbose > 0: 2676e52b07aaSAaron Conole if args.verbose > 1: 2677e52b07aaSAaron Conole logging.basicConfig(level=logging.DEBUG) 2678e52b07aaSAaron Conole 26799feac87bSAaron Conole ovspk = OvsPacket() 268025f16c87SAaron Conole ovsdp = OvsDatapath() 26819feac87bSAaron Conole ovsvp = OvsVport(ovspk) 2682e52b07aaSAaron Conole ovsflow = OvsFlow() 268325f16c87SAaron Conole ndb = NDB() 268425f16c87SAaron Conole 2685bd128f62SAaron Conole sys.setrecursionlimit(100000) 2686bd128f62SAaron Conole 268730d772a0SAdrian Moreno if args.subcommand == "psample-events": 268830d772a0SAdrian Moreno PsampleEvent().read_samples() 268930d772a0SAdrian Moreno 269025f16c87SAaron Conole if hasattr(args, "showdp"): 269125f16c87SAaron Conole found = False 269225f16c87SAaron Conole for iface in ndb.interfaces: 269325f16c87SAaron Conole rep = None 269425f16c87SAaron Conole if args.showdp is None: 269525f16c87SAaron Conole rep = ovsdp.info(iface.ifname, 0) 269625f16c87SAaron Conole elif args.showdp == iface.ifname: 269725f16c87SAaron Conole rep = ovsdp.info(iface.ifname, 0) 269825f16c87SAaron Conole 269925f16c87SAaron Conole if rep is not None: 270025f16c87SAaron Conole found = True 270174cc26f4SAaron Conole print_ovsdp_full(rep, iface.index, ndb, ovsvp) 270225f16c87SAaron Conole 270325f16c87SAaron Conole if not found: 270425f16c87SAaron Conole msg = "No DP found" 270525f16c87SAaron Conole if args.showdp is not None: 270625f16c87SAaron Conole msg += ":'%s'" % args.showdp 270725f16c87SAaron Conole print(msg) 270825f16c87SAaron Conole elif hasattr(args, "adddp"): 27099feac87bSAaron Conole rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk) 271025f16c87SAaron Conole if rep is None: 271125f16c87SAaron Conole print("DP '%s' already exists" % args.adddp) 271225f16c87SAaron Conole else: 271325f16c87SAaron Conole print("DP '%s' added" % args.adddp) 27149feac87bSAaron Conole if args.upcall: 27159feac87bSAaron Conole ovspk.upcall_handler(ovsflow) 271625f16c87SAaron Conole elif hasattr(args, "deldp"): 271725f16c87SAaron Conole ovsdp.destroy(args.deldp) 271874cc26f4SAaron Conole elif hasattr(args, "addif"): 271974cc26f4SAaron Conole rep = ovsdp.info(args.dpname, 0) 272074cc26f4SAaron Conole if rep is None: 272174cc26f4SAaron Conole print("DP '%s' not found." % args.dpname) 272274cc26f4SAaron Conole return 1 27239feac87bSAaron Conole dpindex = rep["dpifindex"] 2724f94ecbc9SAaron Conole rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype, 2725f94ecbc9SAaron Conole args.dport, args.lwt) 272674cc26f4SAaron Conole msg = "vport '%s'" % args.addif 272774cc26f4SAaron Conole if rep and rep["header"]["error"] is None: 272874cc26f4SAaron Conole msg += " added." 272974cc26f4SAaron Conole else: 273074cc26f4SAaron Conole msg += " failed to add." 27319feac87bSAaron Conole if args.upcall: 27329feac87bSAaron Conole if rep is None: 27339feac87bSAaron Conole rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk) 27349feac87bSAaron Conole ovsvp.upcall_handler(ovsflow) 273574cc26f4SAaron Conole elif hasattr(args, "delif"): 273674cc26f4SAaron Conole rep = ovsdp.info(args.dpname, 0) 273774cc26f4SAaron Conole if rep is None: 273874cc26f4SAaron Conole print("DP '%s' not found." % args.dpname) 273974cc26f4SAaron Conole return 1 274074cc26f4SAaron Conole rep = ovsvp.detach(rep["dpifindex"], args.delif) 274174cc26f4SAaron Conole msg = "vport '%s'" % args.delif 274274cc26f4SAaron Conole if rep and rep["header"]["error"] is None: 274374cc26f4SAaron Conole msg += " removed." 274474cc26f4SAaron Conole else: 274574cc26f4SAaron Conole msg += " failed to remove." 2746f94ecbc9SAaron Conole if args.dellink: 2747f94ecbc9SAaron Conole ipr = pyroute2.iproute.IPRoute() 2748f94ecbc9SAaron Conole ipr.link("del", index=ipr.link_lookup(ifname=args.delif)[0]) 2749e52b07aaSAaron Conole elif hasattr(args, "dumpdp"): 2750e52b07aaSAaron Conole rep = ovsdp.info(args.dumpdp, 0) 2751e52b07aaSAaron Conole if rep is None: 2752e52b07aaSAaron Conole print("DP '%s' not found." % args.dumpdp) 2753e52b07aaSAaron Conole return 1 2754e52b07aaSAaron Conole rep = ovsflow.dump(rep["dpifindex"]) 2755e52b07aaSAaron Conole for flow in rep: 2756e52b07aaSAaron Conole print(flow.dpstr(True if args.verbose > 0 else False)) 2757918423fdSAaron Conole elif hasattr(args, "flbr"): 2758918423fdSAaron Conole rep = ovsdp.info(args.flbr, 0) 2759918423fdSAaron Conole if rep is None: 2760918423fdSAaron Conole print("DP '%s' not found." % args.flbr) 2761918423fdSAaron Conole return 1 2762918423fdSAaron Conole flow = OvsFlow.ovs_flow_msg() 2763918423fdSAaron Conole flow.parse(args.flow, args.acts, rep["dpifindex"]) 2764918423fdSAaron Conole ovsflow.add_flow(rep["dpifindex"], flow) 276576035fd1SAaron Conole elif hasattr(args, "flsbr"): 276676035fd1SAaron Conole rep = ovsdp.info(args.flsbr, 0) 276776035fd1SAaron Conole if rep is None: 276876035fd1SAaron Conole print("DP '%s' not found." % args.flsbr) 276976035fd1SAaron Conole ovsflow.del_flows(rep["dpifindex"]) 277025f16c87SAaron Conole 277125f16c87SAaron Conole return 0 277225f16c87SAaron Conole 277325f16c87SAaron Conole 277425f16c87SAaron Conoleif __name__ == "__main__": 277525f16c87SAaron Conole sys.exit(main(sys.argv)) 2776