Commit bd128f62 authored by Aaron Conole's avatar Aaron Conole Committed by Jakub Kicinski

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: default avatarAaron Conole <aconole@redhat.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20240207132416.1488485-3-aconole@redhat.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6e2f90d3
...@@ -502,7 +502,20 @@ test_netlink_checks () { ...@@ -502,7 +502,20 @@ test_netlink_checks () {
wc -l) == 2 ] || \ wc -l) == 2 ] || \
return 1 return 1
info "Checking clone depth"
ERR_MSG="Flow actions may not be safe on all matching packets" 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}") PRE_TEST=$(dmesg | grep -c "${ERR_MSG}")
ovs_add_flow "test_netlink_checks" nv0 \ ovs_add_flow "test_netlink_checks" nv0 \
'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \ 'in_port(1),eth(),eth_type(0x0806),arp()' 'drop(0),2' \
......
...@@ -299,7 +299,7 @@ class ovsactions(nla): ...@@ -299,7 +299,7 @@ class ovsactions(nla):
("OVS_ACTION_ATTR_PUSH_NSH", "none"), ("OVS_ACTION_ATTR_PUSH_NSH", "none"),
("OVS_ACTION_ATTR_POP_NSH", "flag"), ("OVS_ACTION_ATTR_POP_NSH", "flag"),
("OVS_ACTION_ATTR_METER", "none"), ("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_CHECK_PKT_LEN", "none"),
("OVS_ACTION_ATTR_ADD_MPLS", "none"), ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
("OVS_ACTION_ATTR_DEC_TTL", "none"), ("OVS_ACTION_ATTR_DEC_TTL", "none"),
...@@ -465,29 +465,42 @@ class ovsactions(nla): ...@@ -465,29 +465,42 @@ class ovsactions(nla):
print_str += "pop_mpls" print_str += "pop_mpls"
else: else:
datum = self.get_attr(field[0]) 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 return print_str
def parse(self, actstr): def parse(self, actstr):
totallen = len(actstr)
while len(actstr) != 0: while len(actstr) != 0:
parsed = False parsed = False
parencount = 0
if actstr.startswith("drop"): if actstr.startswith("drop"):
# If no reason is provided, the implicit drop is used (i.e no # If no reason is provided, the implicit drop is used (i.e no
# action). If some reason is given, an explicit action is used. # action). If some reason is given, an explicit action is used.
actstr, reason = parse_extract_field( reason = None
actstr, if actstr.startswith("drop("):
"drop(", parencount += 1
"([0-9]+)",
lambda x: int(x, 0), actstr, reason = parse_extract_field(
False, actstr,
None, "drop(",
) "([0-9]+)",
lambda x: int(x, 0),
False,
None,
)
if reason is not None: if reason is not None:
self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason]) self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
parsed = True parsed = True
else: else:
return actstr = actstr[len("drop"): ]
return (totallen - len(actstr))
elif parse_starts_block(actstr, "^(\d+)", False, True): elif parse_starts_block(actstr, "^(\d+)", False, True):
actstr, output = parse_extract_field( actstr, output = parse_extract_field(
...@@ -504,6 +517,7 @@ class ovsactions(nla): ...@@ -504,6 +517,7 @@ class ovsactions(nla):
False, False,
0, 0,
) )
parencount += 1
self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid]) self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
parsed = True parsed = True
...@@ -516,12 +530,22 @@ class ovsactions(nla): ...@@ -516,12 +530,22 @@ class ovsactions(nla):
for flat_act in parse_flat_map: for flat_act in parse_flat_map:
if parse_starts_block(actstr, flat_act[0], False): 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]]) self["attrs"].append([flat_act[1]])
actstr = actstr[strspn(actstr, ", ") :] actstr = actstr[strspn(actstr, ", ") :]
parsed = True 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(") :] actstr = actstr[len("ct(") :]
ctact = ovsactions.ctact() ctact = ovsactions.ctact()
...@@ -553,6 +577,7 @@ class ovsactions(nla): ...@@ -553,6 +577,7 @@ class ovsactions(nla):
natact = ovsactions.ctact.natattr() natact = ovsactions.ctact.natattr()
if actstr.startswith("("): if actstr.startswith("("):
parencount += 1
t = None t = None
actstr = actstr[1:] actstr = actstr[1:]
if actstr.startswith("src"): if actstr.startswith("src"):
...@@ -607,15 +632,29 @@ class ovsactions(nla): ...@@ -607,15 +632,29 @@ class ovsactions(nla):
actstr = actstr[strspn(actstr, ", ") :] actstr = actstr[strspn(actstr, ", ") :]
ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact]) ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
actstr = actstr[strspn(actstr, ",) ") :] actstr = actstr[strspn(actstr, ", ") :]
self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact]) self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
parsed = True 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: if not parsed:
raise ValueError("Action str: '%s' not supported" % actstr) raise ValueError("Action str: '%s' not supported" % actstr)
return (totallen - len(actstr))
class ovskey(nla): class ovskey(nla):
nla_flags = NLA_F_NESTED nla_flags = NLA_F_NESTED
...@@ -2111,6 +2150,8 @@ def main(argv): ...@@ -2111,6 +2150,8 @@ def main(argv):
ovsflow = OvsFlow() ovsflow = OvsFlow()
ndb = NDB() ndb = NDB()
sys.setrecursionlimit(100000)
if hasattr(args, "showdp"): if hasattr(args, "showdp"):
found = False found = False
for iface in ndb.interfaces: for iface in ndb.interfaces:
......
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