xref: /linux/tools/testing/selftests/net/openvswitch/ovs-dpctl.py (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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