selftests: openvswitch: Add validation for the recursion test

Add a test case into the netlink checks that will show the number of
nested action recursions won't exceed 16.  Going to 17 on a small
clone call isn't enough to exhaust the stack on (most) systems, so
it should be safe to run even on systems that don't have the fix
applied.

Signed-off-by: Aaron Conole <aconole@redhat.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20240207132416.1488485-3-aconole@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Aaron Conole 2024-02-07 08:24:16 -05:00 committed by Jakub Kicinski
parent 6e2f90d31f
commit bd128f62c3
2 changed files with 69 additions and 15 deletions

View File

@ -502,7 +502,20 @@ test_netlink_checks () {
wc -l) == 2 ] || \
return 1
info "Checking clone depth"
ERR_MSG="Flow actions may not be safe on all matching packets"
PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
ovs_add_flow "test_netlink_checks" nv0 \
'in_port(1),eth(),eth_type(0x800),ipv4()' \
'clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(clone(drop)))))))))))))))))' \
>/dev/null 2>&1 && return 1
POST_TEST=$(dmesg | grep -c "${ERR_MSG}")
if [ "$PRE_TEST" == "$POST_TEST" ]; then
info "failed - clone depth too large"
return 1
fi
PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
ovs_add_flow "test_netlink_checks" nv0 \
'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \

View File

@ -299,7 +299,7 @@ class ovsactions(nla):
("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_CLONE", "recursive"),
("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
("OVS_ACTION_ATTR_ADD_MPLS", "none"),
("OVS_ACTION_ATTR_DEC_TTL", "none"),
@ -465,29 +465,42 @@ class ovsactions(nla):
print_str += "pop_mpls"
else:
datum = self.get_attr(field[0])
print_str += datum.dpstr(more)
if field[0] == "OVS_ACTION_ATTR_CLONE":
print_str += "clone("
print_str += datum.dpstr(more)
print_str += ")"
else:
print_str += datum.dpstr(more)
return print_str
def parse(self, actstr):
totallen = len(actstr)
while len(actstr) != 0:
parsed = False
parencount = 0
if actstr.startswith("drop"):
# If no reason is provided, the implicit drop is used (i.e no
# action). If some reason is given, an explicit action is used.
actstr, reason = parse_extract_field(
actstr,
"drop(",
"([0-9]+)",
lambda x: int(x, 0),
False,
None,
)
reason = None
if actstr.startswith("drop("):
parencount += 1
actstr, reason = parse_extract_field(
actstr,
"drop(",
"([0-9]+)",
lambda x: int(x, 0),
False,
None,
)
if reason is not None:
self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
parsed = True
else:
return
actstr = actstr[len("drop"): ]
return (totallen - len(actstr))
elif parse_starts_block(actstr, "^(\d+)", False, True):
actstr, output = parse_extract_field(
@ -504,6 +517,7 @@ class ovsactions(nla):
False,
0,
)
parencount += 1
self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
parsed = True
@ -516,12 +530,22 @@ class ovsactions(nla):
for flat_act in parse_flat_map:
if parse_starts_block(actstr, flat_act[0], False):
actstr += len(flat_act[0])
actstr = actstr[len(flat_act[0]):]
self["attrs"].append([flat_act[1]])
actstr = actstr[strspn(actstr, ", ") :]
parsed = True
if parse_starts_block(actstr, "ct(", False):
if parse_starts_block(actstr, "clone(", False):
parencount += 1
subacts = ovsactions()
actstr = actstr[len("clone("):]
parsedLen = subacts.parse(actstr)
lst = []
self["attrs"].append(("OVS_ACTION_ATTR_CLONE", subacts))
actstr = actstr[parsedLen:]
parsed = True
elif parse_starts_block(actstr, "ct(", False):
parencount += 1
actstr = actstr[len("ct(") :]
ctact = ovsactions.ctact()
@ -553,6 +577,7 @@ class ovsactions(nla):
natact = ovsactions.ctact.natattr()
if actstr.startswith("("):
parencount += 1
t = None
actstr = actstr[1:]
if actstr.startswith("src"):
@ -607,15 +632,29 @@ class ovsactions(nla):
actstr = actstr[strspn(actstr, ", ") :]
ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
actstr = actstr[strspn(actstr, ",) ") :]
actstr = actstr[strspn(actstr, ", ") :]
self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
parsed = True
actstr = actstr[strspn(actstr, "), ") :]
actstr = actstr[strspn(actstr, ", ") :]
while parencount > 0:
parencount -= 1
actstr = actstr[strspn(actstr, " "):]
if len(actstr) and actstr[0] != ")":
raise ValueError("Action str: '%s' unbalanced" % actstr)
actstr = actstr[1:]
if len(actstr) and actstr[0] == ")":
return (totallen - len(actstr))
actstr = actstr[strspn(actstr, ", ") :]
if not parsed:
raise ValueError("Action str: '%s' not supported" % actstr)
return (totallen - len(actstr))
class ovskey(nla):
nla_flags = NLA_F_NESTED
@ -2111,6 +2150,8 @@ def main(argv):
ovsflow = OvsFlow()
ndb = NDB()
sys.setrecursionlimit(100000)
if hasattr(args, "showdp"):
found = False
for iface in ndb.interfaces: