Hi VPPeople,

I would like to open a discussion about some strange code and return values
from a few of the NAT CLI and API interface functions.

My quest for a reasonable handling when my management plane attempted to
enable an already-enabled NAT 44 ED feature was handled poorly.  It turns
out,
rather than a negative API return value with an error indicating that the
feature
was already enabled, nor did it return 0 indicating that all was well.
Instead it
returned a positive 1 value.  As there is no indication of return value in
the reply
API call, a normal, negative value was expected.

When I first read through
the vl_api_nat44_ed_plugin_enable_disable_t_handler()
and the underlying nat44_plugin_enable() code, I couldn't see where it even
returned anything other than a straight open-coded 0 return value.

A closer read showed two seriously weird coding issues, both related.  At
the beginning
of nat44_plugin_enable() we find this code from
src/plugin/nat/nat44_ed_api.c
and nat44_ed.c:

int
nat44_plugin_enable (nat44_config_t c)
{
  snat_main_t *sm = &snat_main;

  fail_if_enabled ();

  sm->forwarding_enabled = 0;
  sm->mss_clamping = 0;
  ...

The apparent function fail_if_enabled() isn't a function at all:

#define fail_if_enabled()
  \
  do
   \
    {
  \
      snat_main_t *sm = &snat_main;
  \
      if (PREDICT_FALSE (sm->enabled))
   \
        {
  \
          nat_log_err ("plugin enabled");
  \
          return 1;
  \
        }
  \
    }
  \
  while (0)

It is a single compound statement with the hidden side effect
of returning directly out of the containing function with, get
this, a return value of 1.  This return value is then used in
turn directly as the error return value for an API call:

static void
vl_api_nat44_ed_plugin_enable_disable_t_handler (
  vl_api_nat44_ed_plugin_enable_disable_t *mp)
{
...
  if (mp->enable)
    {
      if ((mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY) ||
          (mp->flags & NAT44_API_IS_CONNECTION_TRACKING))
        {
          rv = VNET_API_ERROR_UNSUPPORTED;
        }
      else
        {
          c.sessions = ntohl (mp->sessions);
          c.inside_vrf = ntohl (mp->inside_vrf);
          c.outside_vrf = ntohl (mp->outside_vrf);

          rv = nat44_plugin_enable (c);
        }
    }
...

OK, I am proposing two fixes here.

First, hiding unexpected control flow in a #define like this is bad for
many reasons.
Allowing for a nominal function to determine if the feature is already
enabled
or not is fine.  It should look like an actual inline function with a
legitimate return value.
It should likely be a TRUE/FALSE "is enabled" testing function,  It should
probably
leave the interpretation of that value to the caller.  That is, the caller
should issue error
messages and generate proper return codes accordingly.

Second, the actual return values for the API should be both listed in the
API error values
enumeration and be negative for errors.  If there is a need, and I
maintainer there is, for
an error code that indicates "already enabled", it should be added if not
already present.

Anyone have any problem with me submitting patches to fix these issues?

Thanks,
jdl
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#22233): https://lists.fd.io/g/vpp-dev/message/22233
Mute This Topic: https://lists.fd.io/mt/95222842/21656
Group Owner: vpp-dev+ow...@lists.fd.io
Unsubscribe: https://lists.fd.io/g/vpp-dev/leave/1480452/21656/631435203/xyzzy 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to