confD7.7: MOP_CREATE request not coming from confD but MOP_DELETE comes

We upgraded confD from 7.3 to 7.7 and with confD 7.7, I am seeing a weird issue with one of the Yang configuration.

When I am configuring the config, my application is not receiving the add config i.e. MOP_CREATE request from the confD. but when I remove the config, my application receives the delete config i.e. MOP_DELETE. I am not sure why confD is not sending MOP_CREATE request. Initially I thought, may be there is some issue with subscription points, but when I observed that delete config is coming than i got confused if the issue is really with subscription point. Please note that in current confD 7.3, I have not seen this issue.

Below is my Yang config

module cwan-gw-acl {
  namespace "http://cisco.com/ns/yang/cwan-gw-acl";
  prefix "gw-acl";

  import ietf-yang-types {
   prefix yang;
  }

  import ietf-inet-types {
    prefix inet;
  }

  import tailf-xsd-types {
    prefix xs;
  }

  import tailf-common {
    prefix tailf;
  }

  organization
    "Cisco Systems, Inc.";

  contact
    "Cisco Systems, Inc.
     Customer Service";

  description
    "config module for cwan-gw-acl
     Copyright (c) 2016-2021 by Cisco Systems, Inc.
     All rights reserved.";

  // =========================================================================
 // REVISION
 // =========================================================================
  revision 2019-07-12 {
    description "Init version";
  }

  typedef action-data-enum {
    default permit;
    type enumeration {
      enum permit;
      enum deny;
    }
  }

  typedef port-range {
    type string {
      length "1..32";
      pattern '\d+|\d+-\d+';
    }
  }

 grouping policy-config-grouping {

     list access-list {
       tailf:info "configure ACL's";
       tailf:cli-oper-info "Display stats of a access-list";
       tailf:cli-suppress-table;
       max-elements 1;
       key "name";

      leaf name {
         tailf:info "name of the access-list";
         type string
         {
             length "1..64";
             tailf:info "max characters allowed - 64";
         }
       }

      list sequence {
         tailf:info "unique sequence number";
         key "seq-value";

          leaf seq-value {
            tailf:info "sequence value";
            type uint16 {
              tailf:info "<1..999>";
              range "1..999";
            }
          }

      leaf protocol {
        tailf:info "name of the protocol";
        mandatory "true";
        type enumeration {
          enum icmp {
            tailf:info "icmp protocol";
          }
          enum udp {
            tailf:info "udp protocol";
          }
          enum tcp {
            tailf:info "tcp protocol";
          }
        }
      }

      leaf source-ip {
        tailf:info "source ip address";
        type inet:ipv4-prefix;
      }

      leaf destination-ip {
        tailf:info "destination ip address";
        type inet:ipv4-prefix;
      }

      leaf source-port {
        tailf:info "source port number";
        //tailf:display-when "../protocol != 'icmp'";
        when "../protocol != 'icmp'";
        type uint32 {
          range "1..65535";
        }
      }

      leaf destination-port {
        tailf:info "destination port number";
        //tailf:display-when "../protocol != 'icmp'";
        when "../protocol != 'icmp'";
        type uint32 {
          range "1..65535";
        }
      }

      leaf action {
        tailf:info "permit or deny";
        mandatory "true";
        type enumeration {
          enum permit;
          enum deny;
        }
      }

  }
  leaf default-action {
    tailf:cli-show-with-default;
    tailf:info "permit or deny";
    type action-data-enum;
  }
  list stats {
    tailf:info "access-list stats detail";
    tailf:callpoint policy_acl_list;
    tailf:cli-suppress-table;
    tailf:cli-show-template-legend "---------------------------------------------------\n";
    config false;
    key id;
    tailf:cli-show-template
   "Hits = $(hits|ljust:5)"+" Seq = $(seq|ljust:4)"+" R: $(rule)\n";

    tailf:cli-show-template-enter "";

    tailf:cli-show-template-footer
   "$(.?\n:"
   +"-------------------------------------------------\n"
   +"% No rules under this access-list.\n\n)";

    leaf id
    {
      tailf:info "access-list rule as a key";
      tailf:cli-drop-node-name;
      type string;
    }
    leaf rule
    {
      tailf:info "access-list rule";
      tailf:cli-drop-node-name;
      type string;
    }
    leaf hits {
      tailf:info "no of hits";
      tailf:cli-drop-node-name;
      type int64;
    }
    leaf seq {
      tailf:info "sequence number";
      tailf:cli-drop-node-name;
      type int64;
    }

  }

}

  }

  container policy {
    tailf:info "policy information";
    tailf:cli-oper-info "Display policy details";
    tailf:cli-incomplete-show-path;
    tailf:cli-add-mode;
    uses policy-config-grouping;
  }

}

In my C application, I have below subscription points:

static t_vconfd_sub_entry acl_subscription_points[] =
{
    {
        .path           = "policy/access-list",
        .name_space     = gw_acl__ns,
        .config_cb      = acl_config_access_list_v4,
        .priority       = VCONFD_SUB_PRIORITY_LAST,
        .del_priority   = VCONFD_SUB_PRIORITY_ONE,
        .num_keys       = 1
    },
   {
        .path           = "policy/access-list/sequence",
       .name_space     = gw_acl__ns,
       .config_cb      = acl_config_access_list_v4_seq,
       .priority       = VCONFD_SUB_PRIORITY_LAST,
       .del_priority   = VCONFD_SUB_PRIORITY_ONE,
       .num_keys       = 2
    },
     {.path = ""}
};

and this is my confd initialization

e_acl_status
acl_confd_init(t_acl_daemon *dcd_p)
{
    int                     status;
    t_vconfd_module_data    mod_data;

    memset_s(&mod_data, sizeof(mod_data), 0, sizeof(mod_data));
    mod_data.opaque_p           = dcd_p;
    mod_data.sub_point_arr      = acl_subscription_points;
    mod_data.val_point_arr      = acl_validation_points;
    mod_data.action_cmd_arr     = acl_action_commands;
    mod_data.data_register_cb   = acl_confd_register_data_cbs;
    mod_data.evt_base_p         = dcd_p->base_event_p;
    mod_data.timer_mgr_p        = dcd_p->timer_mgr_p;
    mod_data.mod_id             = VIP_MODULE_ACLD;
    mod_data.confd_notif_ctxt   = NULL;

   // Connect and initialize acl to confd
   status = vconfd_module_init(&mod_data, NULL, (void *)&dcd_p->vconfd_ctx_p);

   if((status != VCONFD_STATUS_OK) && (status != VCONFD_STATUS_IN_RETRY))
   {
       DEBUG_LOG(ERR,"vconfd module init failed\n");
       return ACL_STATUS_FAIL;
   } else {
       DEBUG_LOG(NOTICE,"vconfd module initialized \n");
   }

    return ACL_STATUS_OK;
}

Can someone please check what I am doing wrong here which is not compatible with confD 7.7

I assume you are using cdb_diff_iterate() to iterate over the changes made to the configuration in the commit-phase. I also assume you are changing the config using NETCONF.
What is the NETCONF <edit-config> RPC you believe does not generate a “MOP_CREATE” when your commit-phase subscriber is iterating over the config changes using cdb_diff_iterate()?

Seems like the issue is with confD7.7, which got fixed in 7.7.3.

  • cdb-subscription: Corrected a cdb_get_modifications() issue introduced
    by ConfD 7.7 when list instances are not included, i.e without
    CDB_GET_MODS_INCLUDE_LISTS flag.
    (ENG-28374, RT:48792, PS-43907, CSCwb07281)

To make it work in confD7.7, you need to set CDB_GET_MODS_INCLUDE_LISTS flag while calling cdb_get_modifications_iter()