diff --git a/include/bm/bm_sim/match_tables.h b/include/bm/bm_sim/match_tables.h index cd13445f7..b1941e43e 100644 --- a/include/bm/bm_sim/match_tables.h +++ b/include/bm/bm_sim/match_tables.h @@ -434,7 +434,7 @@ class MatchTableIndirect : public MatchTableAbstract { std::unique_ptr > match_unit; ActionProfile *action_profile{nullptr}; bool default_set{false}; - ActionEntry empty_action{}; + ActionEntry empty_action{}; // for lookups yielding empty groups }; class MatchTableIndirectWS : public MatchTableIndirect { diff --git a/src/bm_sim/match_tables.cpp b/src/bm_sim/match_tables.cpp index 99932ebbd..0a2fc939c 100644 --- a/src/bm_sim/match_tables.cpp +++ b/src/bm_sim/match_tables.cpp @@ -663,6 +663,12 @@ MatchTableIndirect::lookup(const Packet &pkt, if (!(*hit) && !default_set) return empty_action; const IndirectIndex &index = (*hit) ? *res.value : default_index; + if (index.is_grp() && action_profile->group_is_empty(index.get_grp())) { + BMLOG_ERROR_PKT( + pkt, "Lookup in table '{}' yielded empty group", get_name()); + return empty_action; + } + auto &entry = action_profile->lookup(pkt, index); // TODO(antonin): unfortunately this has to be done at this stage and cannot // be done when inserting a member because for 2 match tables sharing the same diff --git a/tests/test_tables.cpp b/tests/test_tables.cpp index d5d535ff0..c5d612f79 100644 --- a/tests/test_tables.cpp +++ b/tests/test_tables.cpp @@ -1828,6 +1828,27 @@ TEST_F(TableIndirectWS, DefaultGroup) { EXPECT_EQ(rc, MatchErrorCode::SUCCESS); } +// It can be quite complicated to prevent the control-plane from referencing +// empty groups (is it even desirable?). We must at least make sure that we do +// not crash. In the current implementation, I believe the table apply is a +// no-op. +TEST_F(TableIndirectWS, EmptyGroup) { + MatchErrorCode rc; + grp_hdl_t grp; + entry_handle_t lookup_handle; + bool hit; + + auto pkt = get_pkt(64); + + rc = action_profile.create_group(&grp); + EXPECT_EQ(MatchErrorCode::SUCCESS, rc); + + rc = table->set_default_group(grp); + EXPECT_EQ(rc, MatchErrorCode::SUCCESS); + + table->lookup(pkt, &hit, &lookup_handle); +} + TEST_F(TableIndirectWS, CustomGroupSelection) { using GroupSelectionIface = ActionProfile::GroupSelectionIface; using hash_t = ActionProfile::hash_t;