Commit e52b07aa authored by Aaron Conole's avatar Aaron Conole Committed by David S. Miller

selftests: openvswitch: add flow dump support

Add a basic set of fields to print in a 'dpflow' format.  This will be
used by future commits to check for flow fields after parsing, as
well as verifying the flow fields pushed into the kernel from
userspace.
Signed-off-by: default avatarAaron Conole <aconole@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 74cc26f4
...@@ -6,15 +6,21 @@ ...@@ -6,15 +6,21 @@
import argparse import argparse
import errno import errno
import ipaddress
import logging
import sys import sys
import time
try: try:
from pyroute2 import NDB from pyroute2 import NDB
from pyroute2.netlink import NLA_F_NESTED
from pyroute2.netlink import NLM_F_ACK from pyroute2.netlink import NLM_F_ACK
from pyroute2.netlink import NLM_F_DUMP
from pyroute2.netlink import NLM_F_REQUEST from pyroute2.netlink import NLM_F_REQUEST
from pyroute2.netlink import genlmsg from pyroute2.netlink import genlmsg
from pyroute2.netlink import nla from pyroute2.netlink import nla
from pyroute2.netlink import nlmsg_atoms
from pyroute2.netlink.exceptions import NetlinkError from pyroute2.netlink.exceptions import NetlinkError
from pyroute2.netlink.generic import GenericNetlinkSocket from pyroute2.netlink.generic import GenericNetlinkSocket
except ModuleNotFoundError: except ModuleNotFoundError:
...@@ -40,6 +46,36 @@ OVS_VPORT_CMD_DEL = 2 ...@@ -40,6 +46,36 @@ OVS_VPORT_CMD_DEL = 2
OVS_VPORT_CMD_GET = 3 OVS_VPORT_CMD_GET = 3
OVS_VPORT_CMD_SET = 4 OVS_VPORT_CMD_SET = 4
OVS_FLOW_CMD_NEW = 1
OVS_FLOW_CMD_DEL = 2
OVS_FLOW_CMD_GET = 3
OVS_FLOW_CMD_SET = 4
def macstr(mac):
outstr = ":".join(["%02X" % i for i in mac])
return outstr
def convert_mac(mac_str, mask=False):
if mac_str is None or mac_str == "":
mac_str = "00:00:00:00:00:00"
if mask is True and mac_str != "00:00:00:00:00:00":
mac_str = "FF:FF:FF:FF:FF:FF"
mac_split = mac_str.split(":")
ret = bytearray([int(i, 16) for i in mac_split])
return bytes(ret)
def convert_ipv4(ip, mask=False):
if ip is None:
ip = 0
if mask is True:
if ip != 0:
ip = int(ipaddress.IPv4Address(ip)) & 0xFFFFFFFF
return int(ipaddress.IPv4Address(ip))
class ovs_dp_msg(genlmsg): class ovs_dp_msg(genlmsg):
# include the OVS version # include the OVS version
...@@ -49,6 +85,847 @@ class ovs_dp_msg(genlmsg): ...@@ -49,6 +85,847 @@ class ovs_dp_msg(genlmsg):
fields = genlmsg.fields + (("dpifindex", "I"),) fields = genlmsg.fields + (("dpifindex", "I"),)
class ovsactions(nla):
nla_flags = NLA_F_NESTED
nla_map = (
("OVS_ACTION_ATTR_UNSPEC", "none"),
("OVS_ACTION_ATTR_OUTPUT", "uint32"),
("OVS_ACTION_ATTR_USERSPACE", "userspace"),
("OVS_ACTION_ATTR_SET", "none"),
("OVS_ACTION_ATTR_PUSH_VLAN", "none"),
("OVS_ACTION_ATTR_POP_VLAN", "flag"),
("OVS_ACTION_ATTR_SAMPLE", "none"),
("OVS_ACTION_ATTR_RECIRC", "uint32"),
("OVS_ACTION_ATTR_HASH", "none"),
("OVS_ACTION_ATTR_PUSH_MPLS", "none"),
("OVS_ACTION_ATTR_POP_MPLS", "flag"),
("OVS_ACTION_ATTR_SET_MASKED", "none"),
("OVS_ACTION_ATTR_CT", "ctact"),
("OVS_ACTION_ATTR_TRUNC", "uint32"),
("OVS_ACTION_ATTR_PUSH_ETH", "none"),
("OVS_ACTION_ATTR_POP_ETH", "flag"),
("OVS_ACTION_ATTR_CT_CLEAR", "flag"),
("OVS_ACTION_ATTR_PUSH_NSH", "none"),
("OVS_ACTION_ATTR_POP_NSH", "flag"),
("OVS_ACTION_ATTR_METER", "none"),
("OVS_ACTION_ATTR_CLONE", "none"),
("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
("OVS_ACTION_ATTR_ADD_MPLS", "none"),
("OVS_ACTION_ATTR_DEC_TTL", "none"),
)
class ctact(nla):
nla_flags = NLA_F_NESTED
nla_map = (
("OVS_CT_ATTR_NONE", "none"),
("OVS_CT_ATTR_COMMIT", "flag"),
("OVS_CT_ATTR_ZONE", "uint16"),
("OVS_CT_ATTR_MARK", "none"),
("OVS_CT_ATTR_LABELS", "none"),
("OVS_CT_ATTR_HELPER", "asciiz"),
("OVS_CT_ATTR_NAT", "natattr"),
("OVS_CT_ATTR_FORCE_COMMIT", "flag"),
("OVS_CT_ATTR_EVENTMASK", "uint32"),
("OVS_CT_ATTR_TIMEOUT", "asciiz"),
)
class natattr(nla):
nla_flags = NLA_F_NESTED
nla_map = (
("OVS_NAT_ATTR_NONE", "none"),
("OVS_NAT_ATTR_SRC", "flag"),
("OVS_NAT_ATTR_DST", "flag"),
("OVS_NAT_ATTR_IP_MIN", "ipaddr"),
("OVS_NAT_ATTR_IP_MAX", "ipaddr"),
("OVS_NAT_ATTR_PROTO_MIN", "uint16"),
("OVS_NAT_ATTR_PROTO_MAX", "uint16"),
("OVS_NAT_ATTR_PERSISTENT", "flag"),
("OVS_NAT_ATTR_PROTO_HASH", "flag"),
("OVS_NAT_ATTR_PROTO_RANDOM", "flag"),
)
def dpstr(self, more=False):
print_str = "nat("
if self.get_attr("OVS_NAT_ATTR_SRC"):
print_str += "src"
elif self.get_attr("OVS_NAT_ATTR_DST"):
print_str += "dst"
else:
print_str += "XXX-unknown-nat"
if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr(
"OVS_NAT_ATTR_IP_MAX"
):
if self.get_attr("OVS_NAT_ATTR_IP_MIN"):
print_str += "=%s," % str(
self.get_attr("OVS_NAT_ATTR_IP_MIN")
)
if self.get_attr("OVS_NAT_ATTR_IP_MAX"):
print_str += "-%s," % str(
self.get_attr("OVS_NAT_ATTR_IP_MAX")
)
else:
print_str += ","
if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"):
print_str += "proto_min=%d," % self.get_attr(
"OVS_NAT_ATTR_PROTO_MIN"
)
if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"):
print_str += "proto_max=%d," % self.get_attr(
"OVS_NAT_ATTR_PROTO_MAX"
)
if self.get_attr("OVS_NAT_ATTR_PERSISTENT"):
print_str += "persistent,"
if self.get_attr("OVS_NAT_ATTR_HASH"):
print_str += "hash,"
if self.get_attr("OVS_NAT_ATTR_RANDOM"):
print_str += "random"
print_str += ")"
return print_str
def dpstr(self, more=False):
print_str = "ct("
if self.get_attr("OVS_CT_ATTR_COMMIT") is not None:
print_str += "commit,"
if self.get_attr("OVS_CT_ATTR_ZONE") is not None:
print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE")
if self.get_attr("OVS_CT_ATTR_HELPER") is not None:
print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER")
if self.get_attr("OVS_CT_ATTR_NAT") is not None:
print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more)
print_str += ","
if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None:
print_str += "force,"
if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None:
print_str += "emask=0x%X," % self.get_attr(
"OVS_CT_ATTR_EVENTMASK"
)
if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None:
print_str += "timeout=%s" % self.get_attr(
"OVS_CT_ATTR_TIMEOUT"
)
print_str += ")"
return print_str
class userspace(nla):
nla_flags = NLA_F_NESTED
nla_map = (
("OVS_USERSPACE_ATTR_UNUSED", "none"),
("OVS_USERSPACE_ATTR_PID", "uint32"),
("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"),
("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"),
)
def dpstr(self, more=False):
print_str = "userspace("
if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None:
print_str += "pid=%d," % self.get_attr(
"OVS_USERSPACE_ATTR_PID"
)
if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None:
print_str += "userdata="
for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"):
print_str += "%x." % f
if self.get_attr("OVS_USERSPACE_ATTR_TUN_PORT") is not None:
print_str += "egress_tun_port=%d" % self.get_attr(
"OVS_USERSPACE_ATTR_TUN_PORT"
)
print_str += ")"
return print_str
def dpstr(self, more=False):
print_str = ""
for field in self.nla_map:
if field[1] == "none" or self.get_attr(field[0]) is None:
continue
if print_str != "":
print_str += ","
if field[1] == "uint32":
if field[0] == "OVS_ACTION_ATTR_OUTPUT":
print_str += "%d" % int(self.get_attr(field[0]))
elif field[0] == "OVS_ACTION_ATTR_RECIRC":
print_str += "recirc(0x%x)" % int(self.get_attr(field[0]))
elif field[0] == "OVS_ACTION_ATTR_TRUNC":
print_str += "trunc(%d)" % int(self.get_attr(field[0]))
elif field[1] == "flag":
if field[0] == "OVS_ACTION_ATTR_CT_CLEAR":
print_str += "ct_clear"
elif field[0] == "OVS_ACTION_ATTR_POP_VLAN":
print_str += "pop_vlan"
elif field[0] == "OVS_ACTION_ATTR_POP_ETH":
print_str += "pop_eth"
elif field[0] == "OVS_ACTION_ATTR_POP_NSH":
print_str += "pop_nsh"
elif field[0] == "OVS_ACTION_ATTR_POP_MPLS":
print_str += "pop_mpls"
else:
datum = self.get_attr(field[0])
print_str += datum.dpstr(more)
return print_str
class ovskey(nla):
nla_flags = NLA_F_NESTED
nla_map = (
("OVS_KEY_ATTR_UNSPEC", "none"),
("OVS_KEY_ATTR_ENCAP", "none"),
("OVS_KEY_ATTR_PRIORITY", "uint32"),
("OVS_KEY_ATTR_IN_PORT", "uint32"),
("OVS_KEY_ATTR_ETHERNET", "ethaddr"),
("OVS_KEY_ATTR_VLAN", "uint16"),
("OVS_KEY_ATTR_ETHERTYPE", "be16"),
("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"),
("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"),
("OVS_KEY_ATTR_TCP", "ovs_key_tcp"),
("OVS_KEY_ATTR_UDP", "ovs_key_udp"),
("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"),
("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"),
("OVS_KEY_ATTR_ARP", "ovs_key_arp"),
("OVS_KEY_ATTR_ND", "ovs_key_nd"),
("OVS_KEY_ATTR_SKB_MARK", "uint32"),
("OVS_KEY_ATTR_TUNNEL", "none"),
("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"),
("OVS_KEY_ATTR_TCP_FLAGS", "be16"),
("OVS_KEY_ATTR_DP_HASH", "uint32"),
("OVS_KEY_ATTR_RECIRC_ID", "uint32"),
("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"),
("OVS_KEY_ATTR_CT_STATE", "uint32"),
("OVS_KEY_ATTR_CT_ZONE", "uint16"),
("OVS_KEY_ATTR_CT_MARK", "uint32"),
("OVS_KEY_ATTR_CT_LABELS", "none"),
("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"),
("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"),
("OVS_KEY_ATTR_NSH", "none"),
("OVS_KEY_ATTR_PACKET_TYPE", "none"),
("OVS_KEY_ATTR_ND_EXTENSIONS", "none"),
("OVS_KEY_ATTR_TUNNEL_INFO", "none"),
("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"),
)
class ovs_key_proto(nla):
fields = (
("src", "!H"),
("dst", "!H"),
)
fields_map = (
("src", "src", "%d", lambda x: int(x) if x is not None else 0),
("dst", "dst", "%d", lambda x: int(x) if x is not None else 0),
)
def __init__(
self,
protostr,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
self.proto_str = protostr
nla.__init__(
self,
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
def dpstr(self, masked=None, more=False):
outstr = self.proto_str + "("
first = False
for f in self.fields_map:
if first:
outstr += ","
if masked is None:
outstr += "%s=" % f[0]
if isinstance(f[2], str):
outstr += f[2] % self[f[1]]
else:
outstr += f[2](self[f[1]])
first = True
elif more or f[3](masked[f[1]]) != 0:
outstr += "%s=" % f[0]
if isinstance(f[2], str):
outstr += f[2] % self[f[1]]
else:
outstr += f[2](self[f[1]])
outstr += "/"
if isinstance(f[2], str):
outstr += f[2] % masked[f[1]]
else:
outstr += f[2](masked[f[1]])
first = True
outstr += ")"
return outstr
class ethaddr(ovs_key_proto):
fields = (
("src", "!6s"),
("dst", "!6s"),
)
fields_map = (
(
"src",
"src",
macstr,
lambda x: int.from_bytes(x, "big"),
convert_mac,
),
(
"dst",
"dst",
macstr,
lambda x: int.from_bytes(x, "big"),
convert_mac,
),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"eth",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_ipv4(ovs_key_proto):
fields = (
("src", "!I"),
("dst", "!I"),
("proto", "B"),
("tos", "B"),
("ttl", "B"),
("frag", "B"),
)
fields_map = (
(
"src",
"src",
lambda x: str(ipaddress.IPv4Address(x)),
int,
convert_ipv4,
),
(
"dst",
"dst",
lambda x: str(ipaddress.IPv4Address(x)),
int,
convert_ipv4,
),
("proto", "proto", "%d", lambda x: int(x) if x is not None else 0),
("tos", "tos", "%d", lambda x: int(x) if x is not None else 0),
("ttl", "ttl", "%d", lambda x: int(x) if x is not None else 0),
("frag", "frag", "%d", lambda x: int(x) if x is not None else 0),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"ipv4",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_ipv6(ovs_key_proto):
fields = (
("src", "!16s"),
("dst", "!16s"),
("label", "!I"),
("proto", "B"),
("tclass", "B"),
("hlimit", "B"),
("frag", "B"),
)
fields_map = (
(
"src",
"src",
lambda x: str(ipaddress.IPv6Address(x)),
lambda x: int.from_bytes(x, "big"),
lambda x: ipaddress.IPv6Address(x),
),
(
"dst",
"dst",
lambda x: str(ipaddress.IPv6Address(x)),
lambda x: int.from_bytes(x, "big"),
lambda x: ipaddress.IPv6Address(x),
),
("label", "label", "%d", int),
("proto", "proto", "%d", int),
("tclass", "tclass", "%d", int),
("hlimit", "hlimit", "%d", int),
("frag", "frag", "%d", int),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"ipv6",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_tcp(ovs_key_proto):
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"tcp",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_udp(ovs_key_proto):
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"udp",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_sctp(ovs_key_proto):
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"sctp",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_icmp(ovs_key_proto):
fields = (
("type", "B"),
("code", "B"),
)
fields_map = (
("type", "type", "%d", int),
("code", "code", "%d", int),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"icmp",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_icmpv6(ovs_key_icmp):
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"icmpv6",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_arp(ovs_key_proto):
fields = (
("sip", "!I"),
("tip", "!I"),
("op", "!H"),
("sha", "!6s"),
("tha", "!6s"),
("pad", "xx"),
)
fields_map = (
(
"sip",
"sip",
lambda x: str(ipaddress.IPv4Address(x)),
int,
convert_ipv4,
),
(
"tip",
"tip",
lambda x: str(ipaddress.IPv4Address(x)),
int,
convert_ipv4,
),
("op", "op", "%d", lambda x: int(x) if x is not None else 0),
(
"sha",
"sha",
macstr,
lambda x: int.from_bytes(x, "big"),
convert_mac,
),
(
"tha",
"tha",
macstr,
lambda x: int.from_bytes(x, "big"),
convert_mac,
),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"arp",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_nd(ovs_key_proto):
fields = (
("target", "!16s"),
("sll", "!6s"),
("tll", "!6s"),
)
fields_map = (
(
"target",
"target",
lambda x: str(ipaddress.IPv6Address(x)),
lambda x: int.from_bytes(x, "big"),
),
("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")),
("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"nd",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_ct_tuple_ipv4(ovs_key_proto):
fields = (
("src", "!I"),
("dst", "!I"),
("tp_src", "!H"),
("tp_dst", "!H"),
("proto", "B"),
)
fields_map = (
(
"src",
"src",
lambda x: str(ipaddress.IPv4Address(x)),
int,
),
(
"dst",
"dst",
lambda x: str(ipaddress.IPv6Address(x)),
int,
),
("tp_src", "tp_src", "%d", int),
("tp_dst", "tp_dst", "%d", int),
("proto", "proto", "%d", int),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"ct_tuple4",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_ct_tuple_ipv6(nla):
fields = (
("src", "!16s"),
("dst", "!16s"),
("tp_src", "!H"),
("tp_dst", "!H"),
("proto", "B"),
)
fields_map = (
(
"src",
"src",
lambda x: str(ipaddress.IPv6Address(x)),
lambda x: int.from_bytes(x, "big", convertmac),
),
(
"dst",
"dst",
lambda x: str(ipaddress.IPv6Address(x)),
lambda x: int.from_bytes(x, "big"),
),
("tp_src", "tp_src", "%d", int),
("tp_dst", "tp_dst", "%d", int),
("proto", "proto", "%d", int),
)
def __init__(
self,
data=None,
offset=None,
parent=None,
length=None,
init=None,
):
ovskey.ovs_key_proto.__init__(
self,
"ct_tuple6",
data=data,
offset=offset,
parent=parent,
length=length,
init=init,
)
class ovs_key_mpls(nla):
fields = (("lse", ">I"),)
def dpstr(self, mask=None, more=False):
print_str = ""
for field in (
(
"OVS_KEY_ATTR_PRIORITY",
"skb_priority",
"%d",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_SKB_MARK",
"skb_mark",
"%d",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_RECIRC_ID",
"recirc_id",
"0x%08X",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_DP_HASH",
"dp_hash",
"0x%08X",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_CT_STATE",
"ct_state",
"0x%04x",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_CT_ZONE",
"ct_zone",
"0x%04x",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_CT_MARK",
"ct_mark",
"0x%08x",
lambda x: False,
True,
),
(
"OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4",
None,
None,
False,
False,
),
(
"OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6",
None,
None,
False,
False,
),
(
"OVS_KEY_ATTR_IN_PORT",
"in_port",
"%d",
lambda x: True,
True,
),
("OVS_KEY_ATTR_ETHERNET", None, None, False, False),
(
"OVS_KEY_ATTR_ETHERTYPE",
"eth_type",
"0x%04x",
lambda x: int(x) == 0xFFFF,
True,
),
("OVS_KEY_ATTR_IPV4", None, None, False, False),
("OVS_KEY_ATTR_IPV6", None, None, False, False),
("OVS_KEY_ATTR_ARP", None, None, False, False),
("OVS_KEY_ATTR_TCP", None, None, False, False),
(
"OVS_KEY_ATTR_TCP_FLAGS",
"tcp_flags",
"0x%04x",
lambda x: False,
True,
),
("OVS_KEY_ATTR_UDP", None, None, False, False),
("OVS_KEY_ATTR_SCTP", None, None, False, False),
("OVS_KEY_ATTR_ICMP", None, None, False, False),
("OVS_KEY_ATTR_ICMPV6", None, None, False, False),
("OVS_KEY_ATTR_ND", None, None, False, False),
):
v = self.get_attr(field[0])
if v is not None:
m = None if mask is None else mask.get_attr(field[0])
if field[4] is False:
print_str += v.dpstr(m, more)
print_str += ","
else:
if m is None or field[3](m):
print_str += field[1] + "("
print_str += field[2] % v
print_str += "),"
elif more or m != 0:
print_str += field[1] + "("
print_str += (field[2] % v) + "/" + (field[2] % m)
print_str += "),"
return print_str
class OvsDatapath(GenericNetlinkSocket): class OvsDatapath(GenericNetlinkSocket):
OVS_DP_F_VPORT_PIDS = 1 << 1 OVS_DP_F_VPORT_PIDS = 1 << 1
OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3 OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3
...@@ -300,6 +1177,135 @@ class OvsVport(GenericNetlinkSocket): ...@@ -300,6 +1177,135 @@ class OvsVport(GenericNetlinkSocket):
return reply return reply
class OvsFlow(GenericNetlinkSocket):
class ovs_flow_msg(ovs_dp_msg):
nla_map = (
("OVS_FLOW_ATTR_UNSPEC", "none"),
("OVS_FLOW_ATTR_KEY", "ovskey"),
("OVS_FLOW_ATTR_ACTIONS", "ovsactions"),
("OVS_FLOW_ATTR_STATS", "flowstats"),
("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"),
("OVS_FLOW_ATTR_USED", "uint64"),
("OVS_FLOW_ATTR_CLEAR", "none"),
("OVS_FLOW_ATTR_MASK", "ovskey"),
("OVS_FLOW_ATTR_PROBE", "none"),
("OVS_FLOW_ATTR_UFID", "array(uint32)"),
("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"),
)
class flowstats(nla):
fields = (
("packets", "=Q"),
("bytes", "=Q"),
)
def dpstr(self, more=False):
ufid = self.get_attr("OVS_FLOW_ATTR_UFID")
ufid_str = ""
if ufid is not None:
ufid_str = (
"ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format(
ufid[0],
ufid[1] >> 16,
ufid[1] & 0xFFFF,
ufid[2] >> 16,
ufid[2] & 0,
ufid[3],
)
)
key_field = self.get_attr("OVS_FLOW_ATTR_KEY")
keymsg = None
if key_field is not None:
keymsg = key_field
mask_field = self.get_attr("OVS_FLOW_ATTR_MASK")
maskmsg = None
if mask_field is not None:
maskmsg = mask_field
acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS")
actsmsg = None
if acts_field is not None:
actsmsg = acts_field
print_str = ""
if more:
print_str += ufid_str + ","
if keymsg is not None:
print_str += keymsg.dpstr(maskmsg, more)
stats = self.get_attr("OVS_FLOW_ATTR_STATS")
if stats is None:
print_str += " packets:0, bytes:0,"
else:
print_str += " packets:%d, bytes:%d," % (
stats["packets"],
stats["bytes"],
)
used = self.get_attr("OVS_FLOW_ATTR_USED")
print_str += " used:"
if used is None:
print_str += "never,"
else:
used_time = int(used)
cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC)
used_time = (cur_time_sec * 1000) - used_time
print_str += "{}s,".format(used_time / 1000)
print_str += " actions:"
if (
actsmsg is None
or "attrs" not in actsmsg
or len(actsmsg["attrs"]) == 0
):
print_str += "drop"
else:
print_str += actsmsg.dpstr(more)
return print_str
def __init__(self):
GenericNetlinkSocket.__init__(self)
self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg)
def dump(self, dpifindex, flowspec=None):
"""
Returns a list of messages containing flows.
dpifindex should be a valid datapath obtained by calling
into the OvsDatapath lookup
flowpsec is a string which represents a flow in the dpctl
format.
"""
msg = OvsFlow.ovs_flow_msg()
msg["cmd"] = OVS_FLOW_CMD_GET
msg["version"] = OVS_DATAPATH_VERSION
msg["reserved"] = 0
msg["dpifindex"] = dpifindex
msg_flags = NLM_F_REQUEST | NLM_F_ACK
if flowspec is None:
msg_flags |= NLM_F_DUMP
rep = None
try:
rep = self.nlm_request(
msg,
msg_type=self.prid,
msg_flags=msg_flags,
)
except NetlinkError as ne:
raise ne
return rep
def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()): def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME") dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME")
base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS") base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS")
...@@ -340,12 +1346,16 @@ def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()): ...@@ -340,12 +1346,16 @@ def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
def main(argv): def main(argv):
nlmsg_atoms.ovskey = ovskey
nlmsg_atoms.ovsactions = ovsactions
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
"-v", "-v",
"--verbose", "--verbose",
action="count", action="count",
help="Increment 'verbose' output counter.", help="Increment 'verbose' output counter.",
default=0,
) )
subparsers = parser.add_subparsers() subparsers = parser.add_subparsers()
...@@ -387,10 +1397,18 @@ def main(argv): ...@@ -387,10 +1397,18 @@ def main(argv):
delifcmd.add_argument("dpname", help="Datapath Name") delifcmd.add_argument("dpname", help="Datapath Name")
delifcmd.add_argument("delif", help="Interface name for adding") delifcmd.add_argument("delif", help="Interface name for adding")
dumpflcmd = subparsers.add_parser("dump-flows")
dumpflcmd.add_argument("dumpdp", help="Datapath Name")
args = parser.parse_args() args = parser.parse_args()
if args.verbose > 0:
if args.verbose > 1:
logging.basicConfig(level=logging.DEBUG)
ovsdp = OvsDatapath() ovsdp = OvsDatapath()
ovsvp = OvsVport() ovsvp = OvsVport()
ovsflow = OvsFlow()
ndb = NDB() ndb = NDB()
if hasattr(args, "showdp"): if hasattr(args, "showdp"):
...@@ -441,6 +1459,14 @@ def main(argv): ...@@ -441,6 +1459,14 @@ def main(argv):
msg += " removed." msg += " removed."
else: else:
msg += " failed to remove." msg += " failed to remove."
elif hasattr(args, "dumpdp"):
rep = ovsdp.info(args.dumpdp, 0)
if rep is None:
print("DP '%s' not found." % args.dumpdp)
return 1
rep = ovsflow.dump(rep["dpifindex"])
for flow in rep:
print(flow.dpstr(True if args.verbose > 0 else False))
return 0 return 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment