back to topotato report
topotato coverage report
Current view: top level - lib - filter_cli.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 124 732 16.9 %
Date: 2023-02-24 19:38:44 Functions: 5 40 12.5 %

          Line data    Source code
       1             : /*
       2             :  * FRR filter CLI implementation.
       3             :  *
       4             :  * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
       5             :  *                    Rafael Zalamena
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 2 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      20             :  * 02110-1301 USA.
      21             :  */
      22             : 
      23             : #include "zebra.h"
      24             : #include "northbound.h"
      25             : #include "prefix.h"
      26             : 
      27             : #include "lib/command.h"
      28             : #include "lib/filter.h"
      29             : #include "lib/northbound_cli.h"
      30             : #include "lib/plist.h"
      31             : #include "lib/plist_int.h"
      32             : #include "lib/printfrr.h"
      33             : 
      34             : #include "lib/filter_cli_clippy.c"
      35             : 
      36             : #define ACCESS_LIST_STR "Access list entry\n"
      37             : #define ACCESS_LIST_ZEBRA_STR "Access list name\n"
      38             : #define ACCESS_LIST_SEQ_STR                                                    \
      39             :         "Sequence number of an entry\n"                                        \
      40             :         "Sequence number\n"
      41             : #define ACCESS_LIST_ACTION_STR                                                 \
      42             :         "Specify packets to reject\n"                                          \
      43             :         "Specify packets to forward\n"
      44             : #define ACCESS_LIST_REMARK_STR "Access list entry comment\n"
      45             : #define ACCESS_LIST_REMARK_LINE_STR "Comment up to 100 characters\n"
      46             : 
      47             : #define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
      48             : 
      49             : /*
      50             :  * Helper function to generate a sequence number for legacy commands.
      51             :  */
      52           0 : static int acl_get_seq_cb(const struct lyd_node *dnode, void *arg)
      53             : {
      54           0 :         int64_t *seq = arg;
      55           0 :         int64_t cur_seq = yang_dnode_get_uint32(dnode, "sequence");
      56             : 
      57           0 :         if (cur_seq > *seq)
      58           0 :                 *seq = cur_seq;
      59             : 
      60           0 :         return YANG_ITER_CONTINUE;
      61             : }
      62             : 
      63             : /**
      64             :  * Helper function that iterates over the XPath `xpath` on the candidate
      65             :  * configuration in `vty->candidate_config`.
      66             :  *
      67             :  * \param[in] vty shell context with the candidate configuration.
      68             :  * \param[in] xpath the XPath to look for the sequence leaf.
      69             :  * \returns next unused sequence number, -1 if out of range when adding.
      70             :  */
      71           9 : static int64_t acl_get_seq(struct vty *vty, const char *xpath, bool is_remove)
      72             : {
      73           9 :         int64_t seq = 0;
      74             : 
      75           9 :         yang_dnode_iterate(acl_get_seq_cb, &seq, vty->candidate_config->dnode,
      76             :                            "%s/entry", xpath);
      77             : 
      78           9 :         seq += 5;
      79           9 :         if (!is_remove && seq > UINT32_MAX) {
      80           0 :                 vty_out(vty, "%% Malformed sequence value\n");
      81           0 :                 return -1;
      82             :         }
      83             :         return seq;
      84             : }
      85             : 
      86           0 : static int acl_remove_if_empty(struct vty *vty, const char *iptype,
      87             :                                const char *name)
      88             : {
      89           0 :         char xpath[XPATH_MAXLEN];
      90             : 
      91           0 :         snprintf(xpath, sizeof(xpath),
      92             :                  "/frr-filter:lib/access-list[type='%s'][name='%s']/remark",
      93             :                  iptype, name);
      94             :         /* List is not empty if there is a remark, check that: */
      95           0 :         if (yang_dnode_exists(vty->candidate_config->dnode, xpath))
      96             :                 return CMD_SUCCESS;
      97             : 
      98             :         /* Check if we have any entries: */
      99           0 :         snprintf(xpath, sizeof(xpath),
     100             :                  "/frr-filter:lib/access-list[type='%s'][name='%s']", iptype,
     101             :                  name);
     102             :         /*
     103             :          * NOTE: if the list is empty it will return the first sequence
     104             :          * number: 5.
     105             :          */
     106           0 :         if (acl_get_seq(vty, xpath, true) != 5)
     107             :                 return CMD_SUCCESS;
     108             : 
     109             :         /* Nobody is using this list, lets remove it. */
     110           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     111           0 :         return nb_cli_apply_changes(vty, NULL);
     112             : }
     113             : 
     114           0 : static int acl_remove(struct vty *vty, const char *iptype, const char *name,
     115             :                       int64_t sseq)
     116             : {
     117           0 :         char xpath[XPATH_MAXLEN];
     118           0 :         int rv;
     119             : 
     120           0 :         snprintfrr(
     121             :                 xpath, sizeof(xpath),
     122             :                 "/frr-filter:lib/access-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']",
     123             :                 iptype, name, sseq);
     124           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     125             : 
     126           0 :         rv = nb_cli_apply_changes(vty, NULL);
     127           0 :         if (rv == CMD_SUCCESS)
     128           0 :                 return acl_remove_if_empty(vty, iptype, name);
     129             : 
     130             :         return rv;
     131             : }
     132             : 
     133             : /*
     134             :  * Cisco (legacy) access lists.
     135             :  */
     136           0 : DEFPY_YANG(
     137             :         access_list_std, access_list_std_cmd,
     138             :         "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
     139             :         ACCESS_LIST_STR
     140             :         ACCESS_LIST_ZEBRA_STR
     141             :         ACCESS_LIST_SEQ_STR
     142             :         ACCESS_LIST_ACTION_STR
     143             :         "A single host address\n"
     144             :         "Address to match\n"
     145             :         "Address to match\n"
     146             :         "Wildcard bits\n")
     147             : {
     148           0 :         int64_t sseq;
     149           0 :         struct acl_dup_args ada = {};
     150           0 :         char xpath[XPATH_MAXLEN];
     151           0 :         char xpath_entry[XPATH_MAXLEN + 128];
     152             : 
     153             :         /*
     154             :          * Backward compatibility: don't complain about duplicated values,
     155             :          * just silently accept.
     156             :          */
     157           0 :         ada.ada_type = "ipv4";
     158           0 :         ada.ada_name = name;
     159           0 :         ada.ada_action = action;
     160           0 :         if (host_str && mask_str == NULL) {
     161           0 :                 ada.ada_xpath[0] = "./host";
     162           0 :                 ada.ada_value[0] = host_str;
     163           0 :         } else if (host_str && mask_str) {
     164           0 :                 ada.ada_xpath[0] = "./network/address";
     165           0 :                 ada.ada_value[0] = host_str;
     166           0 :                 ada.ada_xpath[1] = "./network/mask";
     167           0 :                 ada.ada_value[1] = mask_str;
     168             :         } else {
     169           0 :                 ada.ada_xpath[0] = "./source-any";
     170           0 :                 ada.ada_value[0] = "";
     171             :         }
     172             : 
     173           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     174             :                 return CMD_SUCCESS;
     175             : 
     176             :         /*
     177             :          * Create the access-list first, so we can generate sequence if
     178             :          * none given (backward compatibility).
     179             :          */
     180           0 :         snprintf(xpath, sizeof(xpath),
     181             :                  "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
     182           0 :         if (seq_str == NULL) {
     183             :                 /* Use XPath to find the next sequence number. */
     184           0 :                 sseq = acl_get_seq(vty, xpath, false);
     185           0 :                 if (sseq < 0)
     186             :                         return CMD_WARNING_CONFIG_FAILED;
     187             : 
     188           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     189             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
     190             :         } else
     191           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     192             :                            "%s/entry[sequence='%s']", xpath, seq_str);
     193             : 
     194           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     195           0 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
     196             : 
     197           0 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
     198           0 :         if (host_str != NULL && mask_str == NULL) {
     199           0 :                 nb_cli_enqueue_change(vty, "./host", NB_OP_MODIFY, host_str);
     200           0 :         } else if (host_str != NULL && mask_str != NULL) {
     201           0 :                 nb_cli_enqueue_change(vty, "./network/address", NB_OP_MODIFY,
     202             :                                       host_str);
     203           0 :                 nb_cli_enqueue_change(vty, "./network/mask", NB_OP_MODIFY,
     204             :                                       mask_str);
     205             :         } else {
     206           0 :                 nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL);
     207             :         }
     208             : 
     209           0 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
     210             : }
     211             : 
     212           0 : DEFPY_YANG(
     213             :         no_access_list_std, no_access_list_std_cmd,
     214             :         "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
     215             :         NO_STR
     216             :         ACCESS_LIST_STR
     217             :         ACCESS_LIST_ZEBRA_STR
     218             :         ACCESS_LIST_SEQ_STR
     219             :         ACCESS_LIST_ACTION_STR
     220             :         "A single host address\n"
     221             :         "Address to match\n"
     222             :         "Address to match\n"
     223             :         "Wildcard bits\n")
     224             : {
     225           0 :         int64_t sseq;
     226           0 :         struct acl_dup_args ada = {};
     227             : 
     228             :         /* If the user provided sequence number, then just go for it. */
     229           0 :         if (seq_str != NULL)
     230           0 :                 return acl_remove(vty, "ipv4", name, seq);
     231             : 
     232             :         /* Otherwise, to keep compatibility, we need to figure it out. */
     233           0 :         ada.ada_type = "ipv4";
     234           0 :         ada.ada_name = name;
     235           0 :         ada.ada_action = action;
     236           0 :         if (host_str && mask_str == NULL) {
     237           0 :                 ada.ada_xpath[0] = "./host";
     238           0 :                 ada.ada_value[0] = host_str;
     239           0 :         } else if (host_str && mask_str) {
     240           0 :                 ada.ada_xpath[0] = "./network/address";
     241           0 :                 ada.ada_value[0] = host_str;
     242           0 :                 ada.ada_xpath[1] = "./network/mask";
     243           0 :                 ada.ada_value[1] = mask_str;
     244             :         } else {
     245           0 :                 ada.ada_xpath[0] = "./source-any";
     246           0 :                 ada.ada_value[0] = "";
     247             :         }
     248             : 
     249           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     250           0 :                 sseq = ada.ada_seq;
     251             :         else
     252             :                 return CMD_WARNING_CONFIG_FAILED;
     253             : 
     254           0 :         return acl_remove(vty, "ipv4", name, sseq);
     255             : }
     256             : 
     257           0 : DEFPY_YANG(
     258             :         access_list_ext, access_list_ext_cmd,
     259             :         "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
     260             :         ACCESS_LIST_STR
     261             :         ACCESS_LIST_ZEBRA_STR
     262             :         ACCESS_LIST_SEQ_STR
     263             :         ACCESS_LIST_ACTION_STR
     264             :         "IPv4 address\n"
     265             :         "Source address to match\n"
     266             :         "Source address mask to apply\n"
     267             :         "Single source host\n"
     268             :         "Source address to match\n"
     269             :         "Any source host\n"
     270             :         "Destination address to match\n"
     271             :         "Destination address mask to apply\n"
     272             :         "Single destination host\n"
     273             :         "Destination address to match\n"
     274             :         "Any destination host\n")
     275             : {
     276           0 :         int idx = 0;
     277           0 :         int64_t sseq;
     278           0 :         struct acl_dup_args ada = {};
     279           0 :         char xpath[XPATH_MAXLEN];
     280           0 :         char xpath_entry[XPATH_MAXLEN + 128];
     281             : 
     282             :         /*
     283             :          * Backward compatibility: don't complain about duplicated values,
     284             :          * just silently accept.
     285             :          */
     286           0 :         ada.ada_type = "ipv4";
     287           0 :         ada.ada_name = name;
     288           0 :         ada.ada_action = action;
     289           0 :         if (src_str && src_mask_str == NULL) {
     290           0 :                 ada.ada_xpath[idx] = "./host";
     291           0 :                 ada.ada_value[idx] = src_str;
     292           0 :                 idx++;
     293           0 :         } else if (src_str && src_mask_str) {
     294           0 :                 ada.ada_xpath[idx] = "./network/address";
     295           0 :                 ada.ada_value[idx] = src_str;
     296           0 :                 idx++;
     297           0 :                 ada.ada_xpath[idx] = "./network/mask";
     298           0 :                 ada.ada_value[idx] = src_mask_str;
     299           0 :                 idx++;
     300             :         } else {
     301           0 :                 ada.ada_xpath[idx] = "./source-any";
     302           0 :                 ada.ada_value[idx] = "";
     303           0 :                 idx++;
     304             :         }
     305             : 
     306           0 :         if (dst_str && dst_mask_str == NULL) {
     307           0 :                 ada.ada_xpath[idx] = "./destination-host";
     308           0 :                 ada.ada_value[idx] = dst_str;
     309           0 :                 idx++;
     310           0 :         } else if (dst_str && dst_mask_str) {
     311           0 :                 ada.ada_xpath[idx] = "./destination-network/address";
     312           0 :                 ada.ada_value[idx] = dst_str;
     313           0 :                 idx++;
     314           0 :                 ada.ada_xpath[idx] = "./destination-network/mask";
     315           0 :                 ada.ada_value[idx] = dst_mask_str;
     316           0 :                 idx++;
     317             :         } else {
     318           0 :                 ada.ada_xpath[idx] = "./destination-any";
     319           0 :                 ada.ada_value[idx] = "";
     320           0 :                 idx++;
     321             :         }
     322             : 
     323           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     324             :                 return CMD_SUCCESS;
     325             : 
     326             :         /*
     327             :          * Create the access-list first, so we can generate sequence if
     328             :          * none given (backward compatibility).
     329             :          */
     330           0 :         snprintf(xpath, sizeof(xpath),
     331             :                  "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
     332           0 :         if (seq_str == NULL) {
     333             :                 /* Use XPath to find the next sequence number. */
     334           0 :                 sseq = acl_get_seq(vty, xpath, false);
     335           0 :                 if (sseq < 0)
     336             :                         return CMD_WARNING_CONFIG_FAILED;
     337             : 
     338           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     339             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
     340             :         } else
     341           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     342             :                            "%s/entry[sequence='%s']", xpath, seq_str);
     343             : 
     344           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     345           0 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
     346             : 
     347           0 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
     348           0 :         if (src_str != NULL && src_mask_str == NULL) {
     349           0 :                 nb_cli_enqueue_change(vty, "./host", NB_OP_MODIFY, src_str);
     350           0 :         } else if (src_str != NULL && src_mask_str != NULL) {
     351           0 :                 nb_cli_enqueue_change(vty, "./network/address", NB_OP_MODIFY,
     352             :                                       src_str);
     353           0 :                 nb_cli_enqueue_change(vty, "./network/mask", NB_OP_MODIFY,
     354             :                                       src_mask_str);
     355             :         } else {
     356           0 :                 nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL);
     357             :         }
     358             : 
     359           0 :         if (dst_str != NULL && dst_mask_str == NULL) {
     360           0 :                 nb_cli_enqueue_change(vty, "./destination-host", NB_OP_MODIFY,
     361             :                                       dst_str);
     362           0 :         } else if (dst_str != NULL && dst_mask_str != NULL) {
     363           0 :                 nb_cli_enqueue_change(vty, "./destination-network/address",
     364             :                                       NB_OP_MODIFY, dst_str);
     365           0 :                 nb_cli_enqueue_change(vty, "./destination-network/mask",
     366             :                                       NB_OP_MODIFY, dst_mask_str);
     367             :         } else {
     368           0 :                 nb_cli_enqueue_change(vty, "./destination-any", NB_OP_CREATE,
     369             :                                       NULL);
     370             :         }
     371             : 
     372           0 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
     373             : }
     374             : 
     375           0 : DEFPY_YANG(
     376             :         no_access_list_ext, no_access_list_ext_cmd,
     377             :         "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
     378             :         NO_STR
     379             :         ACCESS_LIST_STR
     380             :         ACCESS_LIST_ZEBRA_STR
     381             :         ACCESS_LIST_SEQ_STR
     382             :         ACCESS_LIST_ACTION_STR
     383             :         "Any Internet Protocol\n"
     384             :         "Source address to match\n"
     385             :         "Source address mask to apply\n"
     386             :         "Single source host\n"
     387             :         "Source address to match\n"
     388             :         "Any source host\n"
     389             :         "Destination address to match\n"
     390             :         "Destination address mask to apply\n"
     391             :         "Single destination host\n"
     392             :         "Destination address to match\n"
     393             :         "Any destination host\n")
     394             : {
     395           0 :         int idx = 0;
     396           0 :         int64_t sseq;
     397           0 :         struct acl_dup_args ada = {};
     398             : 
     399             :         /* If the user provided sequence number, then just go for it. */
     400           0 :         if (seq_str != NULL)
     401           0 :                 return acl_remove(vty, "ipv4", name, seq);
     402             : 
     403             :         /* Otherwise, to keep compatibility, we need to figure it out. */
     404           0 :         ada.ada_type = "ipv4";
     405           0 :         ada.ada_name = name;
     406           0 :         ada.ada_action = action;
     407           0 :         if (src_str && src_mask_str == NULL) {
     408           0 :                 ada.ada_xpath[idx] = "./host";
     409           0 :                 ada.ada_value[idx] = src_str;
     410           0 :                 idx++;
     411           0 :         } else if (src_str && src_mask_str) {
     412           0 :                 ada.ada_xpath[idx] = "./network/address";
     413           0 :                 ada.ada_value[idx] = src_str;
     414           0 :                 idx++;
     415           0 :                 ada.ada_xpath[idx] = "./network/mask";
     416           0 :                 ada.ada_value[idx] = src_mask_str;
     417           0 :                 idx++;
     418             :         } else {
     419           0 :                 ada.ada_xpath[idx] = "./source-any";
     420           0 :                 ada.ada_value[idx] = "";
     421           0 :                 idx++;
     422             :         }
     423             : 
     424           0 :         if (dst_str && dst_mask_str == NULL) {
     425           0 :                 ada.ada_xpath[idx] = "./destination-host";
     426           0 :                 ada.ada_value[idx] = dst_str;
     427           0 :                 idx++;
     428           0 :         } else if (dst_str && dst_mask_str) {
     429           0 :                 ada.ada_xpath[idx] = "./destination-network/address";
     430           0 :                 ada.ada_value[idx] = dst_str;
     431           0 :                 idx++;
     432           0 :                 ada.ada_xpath[idx] = "./destination-network/mask";
     433           0 :                 ada.ada_value[idx] = dst_mask_str;
     434           0 :                 idx++;
     435             :         } else {
     436           0 :                 ada.ada_xpath[idx] = "./destination-any";
     437           0 :                 ada.ada_value[idx] = "";
     438           0 :                 idx++;
     439             :         }
     440             : 
     441           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     442           0 :                 sseq = ada.ada_seq;
     443             :         else
     444             :                 return CMD_WARNING_CONFIG_FAILED;
     445             : 
     446           0 :         return acl_remove(vty, "ipv4", name, sseq);
     447             : }
     448             : 
     449             : /*
     450             :  * Zebra access lists.
     451             :  */
     452           0 : DEFPY_YANG(
     453             :         access_list, access_list_cmd,
     454             :         "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
     455             :         ACCESS_LIST_STR
     456             :         ACCESS_LIST_ZEBRA_STR
     457             :         ACCESS_LIST_SEQ_STR
     458             :         ACCESS_LIST_ACTION_STR
     459             :         "Prefix to match. e.g. 10.0.0.0/8\n"
     460             :         "Exact match of the prefixes\n"
     461             :         "Match any IPv4\n")
     462             : {
     463           0 :         int64_t sseq;
     464           0 :         struct acl_dup_args ada = {};
     465           0 :         char xpath[XPATH_MAXLEN];
     466           0 :         char xpath_entry[XPATH_MAXLEN + 128];
     467             : 
     468             :         /*
     469             :          * Backward compatibility: don't complain about duplicated values,
     470             :          * just silently accept.
     471             :          */
     472           0 :         ada.ada_type = "ipv4";
     473           0 :         ada.ada_name = name;
     474           0 :         ada.ada_action = action;
     475             : 
     476           0 :         if (prefix_str) {
     477           0 :                 ada.ada_xpath[0] = "./ipv4-prefix";
     478           0 :                 ada.ada_value[0] = prefix_str;
     479           0 :                 if (exact) {
     480           0 :                         ada.ada_xpath[1] = "./ipv4-exact-match";
     481           0 :                         ada.ada_value[1] = "true";
     482             :                 }
     483             :         } else {
     484           0 :                 ada.ada_xpath[0] = "./any";
     485           0 :                 ada.ada_value[0] = "";
     486             :         }
     487             : 
     488           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     489             :                 return CMD_SUCCESS;
     490             : 
     491             :         /*
     492             :          * Create the access-list first, so we can generate sequence if
     493             :          * none given (backward compatibility).
     494             :          */
     495           0 :         snprintf(xpath, sizeof(xpath),
     496             :                  "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
     497           0 :         if (seq_str == NULL) {
     498             :                 /* Use XPath to find the next sequence number. */
     499           0 :                 sseq = acl_get_seq(vty, xpath, false);
     500           0 :                 if (sseq < 0)
     501             :                         return CMD_WARNING_CONFIG_FAILED;
     502             : 
     503           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     504             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
     505             :         } else
     506           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     507             :                            "%s/entry[sequence='%s']", xpath, seq_str);
     508             : 
     509           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     510           0 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
     511             : 
     512           0 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
     513           0 :         if (prefix_str != NULL) {
     514           0 :                 nb_cli_enqueue_change(vty, "./ipv4-prefix", NB_OP_MODIFY,
     515             :                                       prefix_str);
     516           0 :                 nb_cli_enqueue_change(vty, "./ipv4-exact-match", NB_OP_MODIFY,
     517             :                                       exact ? "true" : "false");
     518             :         } else {
     519           0 :                 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
     520             :         }
     521             : 
     522           0 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
     523             : }
     524             : 
     525           0 : DEFPY_YANG(
     526             :         no_access_list, no_access_list_cmd,
     527             :         "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
     528             :         NO_STR
     529             :         ACCESS_LIST_STR
     530             :         ACCESS_LIST_ZEBRA_STR
     531             :         ACCESS_LIST_SEQ_STR
     532             :         ACCESS_LIST_ACTION_STR
     533             :         "Prefix to match. e.g. 10.0.0.0/8\n"
     534             :         "Exact match of the prefixes\n"
     535             :         "Match any IPv4\n")
     536             : {
     537           0 :         int64_t sseq;
     538           0 :         struct acl_dup_args ada = {};
     539             : 
     540             :         /* If the user provided sequence number, then just go for it. */
     541           0 :         if (seq_str != NULL)
     542           0 :                 return acl_remove(vty, "ipv4", name, seq);
     543             : 
     544             :         /* Otherwise, to keep compatibility, we need to figure it out. */
     545           0 :         ada.ada_type = "ipv4";
     546           0 :         ada.ada_name = name;
     547           0 :         ada.ada_action = action;
     548             : 
     549           0 :         if (prefix_str) {
     550           0 :                 ada.ada_xpath[0] = "./ipv4-prefix";
     551           0 :                 ada.ada_value[0] = prefix_str;
     552           0 :                 if (exact) {
     553           0 :                         ada.ada_xpath[1] = "./ipv4-exact-match";
     554           0 :                         ada.ada_value[1] = "true";
     555             :                 }
     556             :         } else {
     557           0 :                 ada.ada_xpath[0] = "./any";
     558           0 :                 ada.ada_value[0] = "";
     559             :         }
     560             : 
     561           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     562           0 :                 sseq = ada.ada_seq;
     563             :         else
     564             :                 return CMD_WARNING_CONFIG_FAILED;
     565             : 
     566           0 :         return acl_remove(vty, "ipv4", name, sseq);
     567             : }
     568             : 
     569           0 : DEFPY_YANG(
     570             :         no_access_list_all, no_access_list_all_cmd,
     571             :         "no access-list WORD$name",
     572             :         NO_STR
     573             :         ACCESS_LIST_STR
     574             :         ACCESS_LIST_ZEBRA_STR)
     575             : {
     576           0 :         char xpath[XPATH_MAXLEN];
     577             : 
     578           0 :         snprintf(xpath, sizeof(xpath),
     579             :                  "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
     580           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     581             : 
     582           0 :         return nb_cli_apply_changes(vty, NULL);
     583             : }
     584             : 
     585           0 : DEFPY_YANG(
     586             :         access_list_remark, access_list_remark_cmd,
     587             :         "access-list WORD$name remark LINE...",
     588             :         ACCESS_LIST_STR
     589             :         ACCESS_LIST_ZEBRA_STR
     590             :         ACCESS_LIST_REMARK_STR
     591             :         ACCESS_LIST_REMARK_LINE_STR)
     592             : {
     593           0 :         int rv;
     594           0 :         char *remark;
     595           0 :         char xpath[XPATH_MAXLEN];
     596             : 
     597           0 :         snprintf(xpath, sizeof(xpath),
     598             :                  "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
     599           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     600             : 
     601           0 :         remark = argv_concat(argv, argc, 3);
     602           0 :         nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
     603           0 :         rv = nb_cli_apply_changes(vty, "%s", xpath);
     604           0 :         XFREE(MTYPE_TMP, remark);
     605             : 
     606           0 :         return rv;
     607             : }
     608             : 
     609           0 : DEFPY_YANG(
     610             :         no_access_list_remark, no_access_list_remark_cmd,
     611             :         "no access-list WORD$name remark",
     612             :         NO_STR
     613             :         ACCESS_LIST_STR
     614             :         ACCESS_LIST_ZEBRA_STR
     615             :         ACCESS_LIST_REMARK_STR)
     616             : {
     617           0 :         char xpath[XPATH_MAXLEN];
     618           0 :         int rv;
     619             : 
     620           0 :         snprintf(xpath, sizeof(xpath),
     621             :                  "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
     622             :                  name);
     623           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     624             : 
     625           0 :         rv = nb_cli_apply_changes(vty, NULL);
     626           0 :         if (rv == CMD_SUCCESS)
     627           0 :                 return acl_remove_if_empty(vty, "ipv4", name);
     628             : 
     629             :         return rv;
     630             : }
     631             : 
     632             : ALIAS(
     633             :         no_access_list_remark, no_access_list_remark_line_cmd,
     634             :         "no access-list WORD$name remark LINE...",
     635             :         NO_STR
     636             :         ACCESS_LIST_STR
     637             :         ACCESS_LIST_ZEBRA_STR
     638             :         ACCESS_LIST_REMARK_STR
     639             :         ACCESS_LIST_REMARK_LINE_STR)
     640             : 
     641           3 : DEFPY_YANG(
     642             :         ipv6_access_list, ipv6_access_list_cmd,
     643             :         "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
     644             :         IPV6_STR
     645             :         ACCESS_LIST_STR
     646             :         ACCESS_LIST_ZEBRA_STR
     647             :         ACCESS_LIST_SEQ_STR
     648             :         ACCESS_LIST_ACTION_STR
     649             :         "IPv6 prefix\n"
     650             :         "Exact match of the prefixes\n"
     651             :         "Match any IPv6\n")
     652             : {
     653           3 :         int64_t sseq;
     654           3 :         struct acl_dup_args ada = {};
     655           3 :         char xpath[XPATH_MAXLEN];
     656           3 :         char xpath_entry[XPATH_MAXLEN + 128];
     657             : 
     658             :         /*
     659             :          * Backward compatibility: don't complain about duplicated values,
     660             :          * just silently accept.
     661             :          */
     662           3 :         ada.ada_type = "ipv6";
     663           3 :         ada.ada_name = name;
     664           3 :         ada.ada_action = action;
     665             : 
     666           3 :         if (prefix_str) {
     667           3 :                 ada.ada_xpath[0] = "./ipv6-prefix";
     668           3 :                 ada.ada_value[0] = prefix_str;
     669           3 :                 if (exact) {
     670           0 :                         ada.ada_xpath[1] = "./ipv6-exact-match";
     671           0 :                         ada.ada_value[1] = "true";
     672             :                 }
     673             :         } else {
     674           0 :                 ada.ada_xpath[0] = "./any";
     675           0 :                 ada.ada_value[0] = "";
     676             :         }
     677             : 
     678           3 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     679             :                 return CMD_SUCCESS;
     680             : 
     681             :         /*
     682             :          * Create the access-list first, so we can generate sequence if
     683             :          * none given (backward compatibility).
     684             :          */
     685           3 :         snprintf(xpath, sizeof(xpath),
     686             :                  "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
     687           3 :         if (seq_str == NULL) {
     688             :                 /* Use XPath to find the next sequence number. */
     689           3 :                 sseq = acl_get_seq(vty, xpath, false);
     690           3 :                 if (sseq < 0)
     691             :                         return CMD_WARNING_CONFIG_FAILED;
     692             : 
     693           3 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     694             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
     695             :         } else
     696           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     697             :                            "%s/entry[sequence='%s']", xpath, seq_str);
     698             : 
     699           3 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     700           3 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
     701             : 
     702           3 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
     703           3 :         if (prefix_str != NULL) {
     704           3 :                 nb_cli_enqueue_change(vty, "./ipv6-prefix", NB_OP_MODIFY,
     705             :                                       prefix_str);
     706           6 :                 nb_cli_enqueue_change(vty, "./ipv6-exact-match", NB_OP_MODIFY,
     707             :                                       exact ? "true" : "false");
     708             :         } else {
     709           0 :                 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
     710             :         }
     711             : 
     712           3 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
     713             : }
     714             : 
     715           0 : DEFPY_YANG(
     716             :         no_ipv6_access_list, no_ipv6_access_list_cmd,
     717             :         "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
     718             :         NO_STR
     719             :         IPV6_STR
     720             :         ACCESS_LIST_STR
     721             :         ACCESS_LIST_ZEBRA_STR
     722             :         ACCESS_LIST_SEQ_STR
     723             :         ACCESS_LIST_ACTION_STR
     724             :         "IPv6 prefix\n"
     725             :         "Exact match of the prefixes\n"
     726             :         "Match any IPv6\n")
     727             : {
     728           0 :         int64_t sseq;
     729           0 :         struct acl_dup_args ada = {};
     730             : 
     731             :         /* If the user provided sequence number, then just go for it. */
     732           0 :         if (seq_str != NULL)
     733           0 :                 return acl_remove(vty, "ipv6", name, seq);
     734             : 
     735             :         /* Otherwise, to keep compatibility, we need to figure it out. */
     736           0 :         ada.ada_type = "ipv6";
     737           0 :         ada.ada_name = name;
     738           0 :         ada.ada_action = action;
     739             : 
     740           0 :         if (prefix_str) {
     741           0 :                 ada.ada_xpath[0] = "./ipv6-prefix";
     742           0 :                 ada.ada_value[0] = prefix_str;
     743           0 :                 if (exact) {
     744           0 :                         ada.ada_xpath[1] = "./ipv6-exact-match";
     745           0 :                         ada.ada_value[1] = "true";
     746             :                 }
     747             :         } else {
     748           0 :                 ada.ada_xpath[0] = "./any";
     749           0 :                 ada.ada_value[0] = "";
     750             :         }
     751             : 
     752           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     753           0 :                 sseq = ada.ada_seq;
     754             :         else
     755             :                 return CMD_WARNING_CONFIG_FAILED;
     756             : 
     757           0 :         return acl_remove(vty, "ipv6", name, sseq);
     758             : }
     759             : 
     760           0 : DEFPY_YANG(
     761             :         no_ipv6_access_list_all, no_ipv6_access_list_all_cmd,
     762             :         "no ipv6 access-list WORD$name",
     763             :         NO_STR
     764             :         IPV6_STR
     765             :         ACCESS_LIST_STR
     766             :         ACCESS_LIST_ZEBRA_STR)
     767             : {
     768           0 :         char xpath[XPATH_MAXLEN];
     769             : 
     770           0 :         snprintf(xpath, sizeof(xpath),
     771             :                  "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
     772           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     773             : 
     774           0 :         return nb_cli_apply_changes(vty, NULL);
     775             : }
     776             : 
     777           0 : DEFPY_YANG(
     778             :         ipv6_access_list_remark, ipv6_access_list_remark_cmd,
     779             :         "ipv6 access-list WORD$name remark LINE...",
     780             :         IPV6_STR
     781             :         ACCESS_LIST_STR
     782             :         ACCESS_LIST_ZEBRA_STR
     783             :         ACCESS_LIST_REMARK_STR
     784             :         ACCESS_LIST_REMARK_LINE_STR)
     785             : {
     786           0 :         int rv;
     787           0 :         char *remark;
     788           0 :         char xpath[XPATH_MAXLEN];
     789             : 
     790           0 :         snprintf(xpath, sizeof(xpath),
     791             :                  "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
     792           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     793             : 
     794           0 :         remark = argv_concat(argv, argc, 4);
     795           0 :         nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
     796           0 :         rv = nb_cli_apply_changes(vty, "%s", xpath);
     797           0 :         XFREE(MTYPE_TMP, remark);
     798             : 
     799           0 :         return rv;
     800             : }
     801             : 
     802           0 : DEFPY_YANG(
     803             :         no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd,
     804             :         "no ipv6 access-list WORD$name remark",
     805             :         NO_STR
     806             :         IPV6_STR
     807             :         ACCESS_LIST_STR
     808             :         ACCESS_LIST_ZEBRA_STR
     809             :         ACCESS_LIST_REMARK_STR)
     810             : {
     811           0 :         char xpath[XPATH_MAXLEN];
     812           0 :         int rv;
     813             : 
     814           0 :         snprintf(xpath, sizeof(xpath),
     815             :                  "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
     816             :                  name);
     817           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     818             : 
     819           0 :         rv = nb_cli_apply_changes(vty, NULL);
     820           0 :         if (rv == CMD_SUCCESS)
     821           0 :                 return acl_remove_if_empty(vty, "ipv6", name);
     822             : 
     823             :         return rv;
     824             : }
     825             : 
     826             : ALIAS(
     827             :         no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd,
     828             :         "no ipv6 access-list ACCESSLIST6_NAME$name remark LINE...",
     829             :         NO_STR
     830             :         IPV6_STR
     831             :         ACCESS_LIST_STR
     832             :         ACCESS_LIST_ZEBRA_STR
     833             :         ACCESS_LIST_REMARK_STR
     834             :         ACCESS_LIST_REMARK_LINE_STR)
     835             : 
     836           0 : DEFPY_YANG(
     837             :         mac_access_list, mac_access_list_cmd,
     838             :         "mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
     839             :         MAC_STR
     840             :         ACCESS_LIST_STR
     841             :         ACCESS_LIST_ZEBRA_STR
     842             :         ACCESS_LIST_SEQ_STR
     843             :         ACCESS_LIST_ACTION_STR
     844             :         "MAC address\n"
     845             :         "Match any MAC address\n")
     846             : {
     847           0 :         int64_t sseq;
     848           0 :         struct acl_dup_args ada = {};
     849           0 :         char xpath[XPATH_MAXLEN];
     850           0 :         char xpath_entry[XPATH_MAXLEN + 128];
     851             : 
     852             :         /*
     853             :          * Backward compatibility: don't complain about duplicated values,
     854             :          * just silently accept.
     855             :          */
     856           0 :         ada.ada_type = "mac";
     857           0 :         ada.ada_name = name;
     858           0 :         ada.ada_action = action;
     859             : 
     860           0 :         if (mac_str) {
     861           0 :                 ada.ada_xpath[0] = "./mac";
     862           0 :                 ada.ada_value[0] = mac_str;
     863             :         } else {
     864           0 :                 ada.ada_xpath[0] = "./any";
     865           0 :                 ada.ada_value[0] = "";
     866             :         }
     867             : 
     868           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     869             :                 return CMD_SUCCESS;
     870             : 
     871             :         /*
     872             :          * Create the access-list first, so we can generate sequence if
     873             :          * none given (backward compatibility).
     874             :          */
     875           0 :         snprintf(xpath, sizeof(xpath),
     876             :                  "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
     877           0 :         if (seq_str == NULL) {
     878             :                 /* Use XPath to find the next sequence number. */
     879           0 :                 sseq = acl_get_seq(vty, xpath, false);
     880           0 :                 if (sseq < 0)
     881             :                         return CMD_WARNING_CONFIG_FAILED;
     882             : 
     883           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     884             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
     885             :         } else
     886           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
     887             :                            "%s/entry[sequence='%s']", xpath, seq_str);
     888             : 
     889           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     890           0 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
     891             : 
     892           0 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
     893           0 :         if (mac_str != NULL) {
     894           0 :                 nb_cli_enqueue_change(vty, "./mac", NB_OP_MODIFY, mac_str);
     895             :         } else {
     896           0 :                 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
     897             :         }
     898             : 
     899           0 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
     900             : }
     901             : 
     902           0 : DEFPY_YANG(
     903             :         no_mac_access_list, no_mac_access_list_cmd,
     904             :         "no mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
     905             :         NO_STR
     906             :         MAC_STR
     907             :         ACCESS_LIST_STR
     908             :         ACCESS_LIST_ZEBRA_STR
     909             :         ACCESS_LIST_SEQ_STR
     910             :         ACCESS_LIST_ACTION_STR
     911             :         "MAC address\n"
     912             :         "Match any MAC address\n")
     913             : {
     914           0 :         int64_t sseq;
     915           0 :         struct acl_dup_args ada = {};
     916             : 
     917             :         /* If the user provided sequence number, then just go for it. */
     918           0 :         if (seq_str != NULL)
     919           0 :                 return acl_remove(vty, "mac", name, seq);
     920             : 
     921             :         /* Otherwise, to keep compatibility, we need to figure it out. */
     922           0 :         ada.ada_type = "mac";
     923           0 :         ada.ada_name = name;
     924           0 :         ada.ada_action = action;
     925             : 
     926           0 :         if (mac_str) {
     927           0 :                 ada.ada_xpath[0] = "./mac";
     928           0 :                 ada.ada_value[0] = mac_str;
     929             :         } else {
     930           0 :                 ada.ada_xpath[0] = "./any";
     931           0 :                 ada.ada_value[0] = "";
     932             :         }
     933             : 
     934           0 :         if (acl_is_dup(vty->candidate_config->dnode, &ada))
     935           0 :                 sseq = ada.ada_seq;
     936             :         else
     937             :                 return CMD_WARNING_CONFIG_FAILED;
     938             : 
     939           0 :         return acl_remove(vty, "mac", name, sseq);
     940             : }
     941             : 
     942           0 : DEFPY_YANG(
     943             :         no_mac_access_list_all, no_mac_access_list_all_cmd,
     944             :         "no mac access-list ACCESSLIST_MAC_NAME$name",
     945             :         NO_STR
     946             :         MAC_STR
     947             :         ACCESS_LIST_STR
     948             :         ACCESS_LIST_ZEBRA_STR)
     949             : {
     950           0 :         char xpath[XPATH_MAXLEN];
     951             : 
     952           0 :         snprintf(xpath, sizeof(xpath),
     953             :                  "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
     954           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
     955             : 
     956           0 :         return nb_cli_apply_changes(vty, NULL);
     957             : }
     958             : 
     959           0 : DEFPY_YANG(
     960             :         mac_access_list_remark, mac_access_list_remark_cmd,
     961             :         "mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
     962             :         MAC_STR
     963             :         ACCESS_LIST_STR
     964             :         ACCESS_LIST_ZEBRA_STR
     965             :         ACCESS_LIST_REMARK_STR
     966             :         ACCESS_LIST_REMARK_LINE_STR)
     967             : {
     968           0 :         int rv;
     969           0 :         char *remark;
     970           0 :         char xpath[XPATH_MAXLEN];
     971             : 
     972           0 :         snprintf(xpath, sizeof(xpath),
     973             :                  "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
     974           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
     975             : 
     976           0 :         remark = argv_concat(argv, argc, 4);
     977           0 :         nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
     978           0 :         rv = nb_cli_apply_changes(vty, "%s", xpath);
     979           0 :         XFREE(MTYPE_TMP, remark);
     980             : 
     981           0 :         return rv;
     982             : }
     983             : 
     984           0 : DEFPY_YANG(
     985             :         no_mac_access_list_remark, no_mac_access_list_remark_cmd,
     986             :         "no mac access-list ACCESSLIST_MAC_NAME$name remark",
     987             :         NO_STR
     988             :         MAC_STR
     989             :         ACCESS_LIST_STR
     990             :         ACCESS_LIST_ZEBRA_STR
     991             :         ACCESS_LIST_REMARK_STR)
     992             : {
     993           0 :         char xpath[XPATH_MAXLEN];
     994           0 :         int rv;
     995             : 
     996           0 :         snprintf(xpath, sizeof(xpath),
     997             :                  "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
     998             :                  name);
     999           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1000             : 
    1001           0 :         rv = nb_cli_apply_changes(vty, NULL);
    1002           0 :         if (rv == CMD_SUCCESS)
    1003           0 :                 return acl_remove_if_empty(vty, "mac", name);
    1004             : 
    1005             :         return rv;
    1006             : }
    1007             : 
    1008             : ALIAS(
    1009             :         no_mac_access_list_remark, no_mac_access_list_remark_line_cmd,
    1010             :         "no mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
    1011             :         NO_STR
    1012             :         MAC_STR
    1013             :         ACCESS_LIST_STR
    1014             :         ACCESS_LIST_ZEBRA_STR
    1015             :         ACCESS_LIST_REMARK_STR
    1016             :         ACCESS_LIST_REMARK_LINE_STR)
    1017             : 
    1018           0 : int access_list_cmp(const struct lyd_node *dnode1,
    1019             :                     const struct lyd_node *dnode2)
    1020             : {
    1021           0 :         uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
    1022           0 :         uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
    1023             : 
    1024           0 :         return seq1 - seq2;
    1025             : }
    1026             : 
    1027           0 : void access_list_show(struct vty *vty, const struct lyd_node *dnode,
    1028             :                       bool show_defaults)
    1029             : {
    1030           0 :         int type = yang_dnode_get_enum(dnode, "../type");
    1031           0 :         struct prefix p;
    1032           0 :         bool is_any;
    1033           0 :         bool is_exact = false;
    1034           0 :         bool cisco_style = false;
    1035           0 :         bool cisco_extended = false;
    1036           0 :         struct in_addr addr, mask;
    1037           0 :         char macstr[PREFIX2STR_BUFFER];
    1038             : 
    1039           0 :         is_any = yang_dnode_exists(dnode, "./any");
    1040           0 :         switch (type) {
    1041           0 :         case YALT_IPV4:
    1042           0 :                 if (is_any)
    1043             :                         break;
    1044             : 
    1045           0 :                 if (yang_dnode_exists(dnode, "./host")
    1046           0 :                     || yang_dnode_exists(dnode, "./network/address")
    1047           0 :                     || yang_dnode_exists(dnode, "./source-any")) {
    1048           0 :                         cisco_style = true;
    1049           0 :                         if (yang_dnode_exists(dnode, "./destination-host")
    1050           0 :                             || yang_dnode_exists(
    1051             :                                     dnode, "./destination-network/address")
    1052           0 :                             || yang_dnode_exists(dnode, "./destination-any"))
    1053             :                                 cisco_extended = true;
    1054             :                 } else {
    1055           0 :                         yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
    1056           0 :                         is_exact = yang_dnode_get_bool(dnode,
    1057             :                                                        "./ipv4-exact-match");
    1058             :                 }
    1059             :                 break;
    1060           0 :         case YALT_IPV6: /* ipv6 */
    1061           0 :                 vty_out(vty, "ipv6 ");
    1062           0 :                 if (is_any)
    1063             :                         break;
    1064             : 
    1065           0 :                 yang_dnode_get_prefix(&p, dnode, "./ipv6-prefix");
    1066           0 :                 is_exact = yang_dnode_get_bool(dnode, "./ipv6-exact-match");
    1067           0 :                 break;
    1068           0 :         case YALT_MAC: /* mac */
    1069           0 :                 vty_out(vty, "mac ");
    1070           0 :                 if (is_any)
    1071             :                         break;
    1072             : 
    1073           0 :                 yang_dnode_get_prefix(&p, dnode, "./mac");
    1074           0 :                 break;
    1075             :         }
    1076             : 
    1077           0 :         vty_out(vty, "access-list %s seq %s %s",
    1078             :                 yang_dnode_get_string(dnode, "../name"),
    1079             :                 yang_dnode_get_string(dnode, "./sequence"),
    1080             :                 yang_dnode_get_string(dnode, "./action"));
    1081             : 
    1082             :         /* Handle Cisco style access lists. */
    1083           0 :         if (cisco_style) {
    1084           0 :                 if (cisco_extended)
    1085           0 :                         vty_out(vty, " ip");
    1086             : 
    1087           0 :                 if (yang_dnode_exists(dnode, "./network")) {
    1088           0 :                         yang_dnode_get_ipv4(&addr, dnode, "./network/address");
    1089           0 :                         yang_dnode_get_ipv4(&mask, dnode, "./network/mask");
    1090           0 :                         vty_out(vty, " %pI4 %pI4", &addr, &mask);
    1091           0 :                 } else if (yang_dnode_exists(dnode, "./host")) {
    1092           0 :                         if (cisco_extended)
    1093           0 :                                 vty_out(vty, " host");
    1094             : 
    1095           0 :                         vty_out(vty, " %s",
    1096             :                                 yang_dnode_get_string(dnode, "./host"));
    1097           0 :                 } else if (yang_dnode_exists(dnode, "./source-any"))
    1098           0 :                         vty_out(vty, " any");
    1099             : 
    1100             :                 /* Not extended, exit earlier. */
    1101           0 :                 if (!cisco_extended) {
    1102           0 :                         vty_out(vty, "\n");
    1103           0 :                         return;
    1104             :                 }
    1105             : 
    1106             :                 /* Handle destination address. */
    1107           0 :                 if (yang_dnode_exists(dnode, "./destination-network")) {
    1108           0 :                         yang_dnode_get_ipv4(&addr, dnode,
    1109             :                                             "./destination-network/address");
    1110           0 :                         yang_dnode_get_ipv4(&mask, dnode,
    1111             :                                             "./destination-network/mask");
    1112           0 :                         vty_out(vty, " %pI4 %pI4", &addr, &mask);
    1113           0 :                 } else if (yang_dnode_exists(dnode, "./destination-host"))
    1114           0 :                         vty_out(vty, " host %s",
    1115             :                                 yang_dnode_get_string(dnode,
    1116             :                                                       "./destination-host"));
    1117           0 :                 else if (yang_dnode_exists(dnode, "./destination-any"))
    1118           0 :                         vty_out(vty, " any");
    1119             : 
    1120           0 :                 vty_out(vty, "\n");
    1121           0 :                 return;
    1122             :         }
    1123             : 
    1124             :         /* Zebra style access list. */
    1125           0 :         if (!is_any) {
    1126             :                 /* If type is MAC don't show '/mask'. */
    1127           0 :                 if (type == 2 /* mac */) {
    1128           0 :                         prefix_mac2str(&p.u.prefix_eth, macstr, sizeof(macstr));
    1129           0 :                         vty_out(vty, " %s", macstr);
    1130             :                 } else
    1131           0 :                         vty_out(vty, " %pFX", &p);
    1132             :         } else
    1133           0 :                 vty_out(vty, " any");
    1134             : 
    1135           0 :         if (is_exact)
    1136           0 :                 vty_out(vty, " exact-match");
    1137             : 
    1138           0 :         vty_out(vty, "\n");
    1139             : }
    1140             : 
    1141           0 : void access_list_remark_show(struct vty *vty, const struct lyd_node *dnode,
    1142             :                              bool show_defaults)
    1143             : {
    1144           0 :         int type = yang_dnode_get_enum(dnode, "../type");
    1145             : 
    1146           0 :         switch (type) {
    1147             :         case YALT_IPV4:
    1148             :                 break;
    1149           0 :         case YALT_IPV6:
    1150           0 :                 vty_out(vty, "ipv6 ");
    1151           0 :                 break;
    1152           0 :         case YALT_MAC:
    1153           0 :                 vty_out(vty, "mac ");
    1154           0 :                 break;
    1155             :         }
    1156             : 
    1157           0 :         vty_out(vty, "access-list %s remark %s\n",
    1158             :                 yang_dnode_get_string(dnode, "../name"),
    1159             :                 yang_dnode_get_string(dnode, NULL));
    1160           0 : }
    1161             : 
    1162             : /*
    1163             :  * Prefix lists.
    1164             :  */
    1165             : 
    1166             : /**
    1167             :  * Remove main data structure prefix list if there are no more entries or
    1168             :  * remark. This fixes compatibility with old CLI and tests.
    1169             :  */
    1170           0 : static int plist_remove_if_empty(struct vty *vty, const char *iptype,
    1171             :                                  const char *name)
    1172             : {
    1173           0 :         char xpath[XPATH_MAXLEN];
    1174             : 
    1175           0 :         snprintf(xpath, sizeof(xpath),
    1176             :                  "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
    1177             :                  iptype, name);
    1178             :         /* List is not empty if there is a remark, check that: */
    1179           0 :         if (yang_dnode_exists(vty->candidate_config->dnode, xpath))
    1180             :                 return CMD_SUCCESS;
    1181             : 
    1182             :         /* Check if we have any entries: */
    1183           0 :         snprintf(xpath, sizeof(xpath),
    1184             :                  "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype,
    1185             :                  name);
    1186             :         /*
    1187             :          * NOTE: if the list is empty it will return the first sequence
    1188             :          * number: 5.
    1189             :          */
    1190           0 :         if (acl_get_seq(vty, xpath, true) != 5)
    1191             :                 return CMD_SUCCESS;
    1192             : 
    1193             :         /* Nobody is using this list, lets remove it. */
    1194           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1195           0 :         return nb_cli_apply_changes(vty, NULL);
    1196             : }
    1197             : 
    1198           0 : static int plist_remove(struct vty *vty, const char *iptype, const char *name,
    1199             :                         const char *seq, const char *action,
    1200             :                         union prefixconstptr prefix, int ge, int le)
    1201             : {
    1202           0 :         int64_t sseq;
    1203           0 :         struct plist_dup_args pda = {};
    1204           0 :         char xpath[XPATH_MAXLEN];
    1205           0 :         char xpath_entry[XPATH_MAXLEN + 32];
    1206           0 :         int rv;
    1207             : 
    1208             :         /* If the user provided sequence number, then just go for it. */
    1209           0 :         if (seq != NULL) {
    1210           0 :                 snprintf(
    1211             :                         xpath, sizeof(xpath),
    1212             :                         "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
    1213             :                         iptype, name, seq);
    1214           0 :                 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1215             : 
    1216           0 :                 rv = nb_cli_apply_changes(vty, NULL);
    1217           0 :                 if (rv == CMD_SUCCESS)
    1218           0 :                         return plist_remove_if_empty(vty, iptype, name);
    1219             : 
    1220             :                 return rv;
    1221             :         }
    1222             : 
    1223             :         /* Otherwise, to keep compatibility, we need to figure it out. */
    1224           0 :         pda.pda_type = iptype;
    1225           0 :         pda.pda_name = name;
    1226           0 :         pda.pda_action = action;
    1227           0 :         if (prefix.p) {
    1228           0 :                 prefix_copy(&pda.prefix, prefix);
    1229           0 :                 apply_mask(&pda.prefix);
    1230           0 :                 pda.ge = ge;
    1231           0 :                 pda.le = le;
    1232             :         } else {
    1233           0 :                 pda.any = true;
    1234             :         }
    1235             : 
    1236           0 :         if (plist_is_dup(vty->candidate_config->dnode, &pda))
    1237           0 :                 sseq = pda.pda_seq;
    1238             :         else
    1239             :                 return CMD_WARNING_CONFIG_FAILED;
    1240             : 
    1241           0 :         snprintfrr(
    1242             :                 xpath_entry, sizeof(xpath_entry),
    1243             :                 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']",
    1244             :                 iptype, name, sseq);
    1245           0 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
    1246             : 
    1247           0 :         rv = nb_cli_apply_changes(vty, NULL);
    1248           0 :         if (rv == CMD_SUCCESS)
    1249           0 :                 return plist_remove_if_empty(vty, iptype, name);
    1250             : 
    1251             :         return rv;
    1252             : }
    1253             : 
    1254           2 : DEFPY_YANG(
    1255             :         ip_prefix_list, ip_prefix_list_cmd,
    1256             :         "ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>",
    1257             :         IP_STR
    1258             :         PREFIX_LIST_STR
    1259             :         PREFIX_LIST_NAME_STR
    1260             :         ACCESS_LIST_SEQ_STR
    1261             :         ACCESS_LIST_ACTION_STR
    1262             :         "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n"
    1263             :         "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
    1264             :         "Minimum prefix length to be matched\n"
    1265             :         "Minimum prefix length\n"
    1266             :         "Maximum prefix length to be matched\n"
    1267             :         "Maximum prefix length\n")
    1268             : {
    1269           2 :         int64_t sseq;
    1270           2 :         struct plist_dup_args pda = {};
    1271           2 :         char xpath[XPATH_MAXLEN];
    1272           2 :         char xpath_entry[XPATH_MAXLEN + 128];
    1273             : 
    1274             :         /*
    1275             :          * Backward compatibility: don't complain about duplicated values,
    1276             :          * just silently accept.
    1277             :          */
    1278           2 :         pda.pda_type = "ipv4";
    1279           2 :         pda.pda_name = name;
    1280           2 :         pda.pda_action = action;
    1281           2 :         if (prefix_str) {
    1282           2 :                 prefix_copy(&pda.prefix, prefix);
    1283           2 :                 pda.ge = ge;
    1284           2 :                 pda.le = le;
    1285             :         } else {
    1286           0 :                 pda.any = true;
    1287             :         }
    1288             : 
    1289           2 :         if (plist_is_dup(vty->candidate_config->dnode, &pda))
    1290             :                 return CMD_SUCCESS;
    1291             : 
    1292             :         /*
    1293             :          * Create the prefix-list first, so we can generate sequence if
    1294             :          * none given (backward compatibility).
    1295             :          */
    1296           2 :         snprintf(xpath, sizeof(xpath),
    1297             :                  "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
    1298           2 :         if (seq_str == NULL) {
    1299             :                 /* Use XPath to find the next sequence number. */
    1300           0 :                 sseq = acl_get_seq(vty, xpath, false);
    1301           0 :                 if (sseq < 0)
    1302             :                         return CMD_WARNING_CONFIG_FAILED;
    1303             : 
    1304           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
    1305             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
    1306             :         } else
    1307           2 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
    1308             :                            "%s/entry[sequence='%s']", xpath, seq_str);
    1309             : 
    1310           2 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
    1311           2 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
    1312             : 
    1313           2 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
    1314           2 :         if (prefix_str != NULL) {
    1315           2 :                 nb_cli_enqueue_change(vty, "./ipv4-prefix", NB_OP_MODIFY,
    1316             :                                       prefix_str);
    1317             : 
    1318           2 :                 if (ge_str) {
    1319           0 :                         nb_cli_enqueue_change(
    1320             :                                 vty, "./ipv4-prefix-length-greater-or-equal",
    1321             :                                 NB_OP_MODIFY, ge_str);
    1322             :                 } else {
    1323             :                         /*
    1324             :                          * Remove old ge if not being modified
    1325             :                          */
    1326           2 :                         nb_cli_enqueue_change(
    1327             :                                 vty, "./ipv4-prefix-length-greater-or-equal",
    1328             :                                 NB_OP_DESTROY, NULL);
    1329             :                 }
    1330             : 
    1331           2 :                 if (le_str) {
    1332           1 :                         nb_cli_enqueue_change(
    1333             :                                 vty, "./ipv4-prefix-length-lesser-or-equal",
    1334             :                                 NB_OP_MODIFY, le_str);
    1335             :                 } else {
    1336             :                         /*
    1337             :                          * Remove old le if not being modified
    1338             :                          */
    1339           1 :                         nb_cli_enqueue_change(
    1340             :                                 vty, "./ipv4-prefix-length-lesser-or-equal",
    1341             :                                 NB_OP_DESTROY, NULL);
    1342             :                 }
    1343             :         } else {
    1344           0 :                 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
    1345             :         }
    1346             : 
    1347           2 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
    1348             : }
    1349             : 
    1350           0 : DEFPY_YANG(
    1351             :         no_ip_prefix_list, no_ip_prefix_list_cmd,
    1352             :         "no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>",
    1353             :         NO_STR
    1354             :         IP_STR
    1355             :         PREFIX_LIST_STR
    1356             :         PREFIX_LIST_NAME_STR
    1357             :         ACCESS_LIST_SEQ_STR
    1358             :         ACCESS_LIST_ACTION_STR
    1359             :         "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n"
    1360             :         "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
    1361             :         "Minimum prefix length to be matched\n"
    1362             :         "Minimum prefix length\n"
    1363             :         "Maximum prefix length to be matched\n"
    1364             :         "Maximum prefix length\n")
    1365             : {
    1366           0 :         return plist_remove(vty, "ipv4", name, seq_str, action,
    1367           0 :                             prefix_str ? prefix : NULL, ge, le);
    1368             : }
    1369             : 
    1370           0 : DEFPY_YANG(
    1371             :         no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd,
    1372             :         "no ip prefix-list WORD$name seq (1-4294967295)$seq",
    1373             :         NO_STR
    1374             :         IP_STR
    1375             :         PREFIX_LIST_STR
    1376             :         PREFIX_LIST_NAME_STR
    1377             :         ACCESS_LIST_SEQ_STR)
    1378             : {
    1379           0 :         return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0);
    1380             : }
    1381             : 
    1382           0 : DEFPY_YANG(
    1383             :         no_ip_prefix_list_all, no_ip_prefix_list_all_cmd,
    1384             :         "no ip prefix-list WORD$name",
    1385             :         NO_STR
    1386             :         IP_STR
    1387             :         PREFIX_LIST_STR
    1388             :         PREFIX_LIST_NAME_STR)
    1389             : {
    1390           0 :         char xpath[XPATH_MAXLEN];
    1391             : 
    1392           0 :         snprintf(xpath, sizeof(xpath),
    1393             :                  "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
    1394           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1395             : 
    1396           0 :         return nb_cli_apply_changes(vty, NULL);
    1397             : }
    1398             : 
    1399           0 : DEFPY_YANG(
    1400             :         ip_prefix_list_remark, ip_prefix_list_remark_cmd,
    1401             :         "ip prefix-list WORD$name description LINE...",
    1402             :         IP_STR
    1403             :         PREFIX_LIST_STR
    1404             :         PREFIX_LIST_NAME_STR
    1405             :         ACCESS_LIST_REMARK_STR
    1406             :         ACCESS_LIST_REMARK_LINE_STR)
    1407             : {
    1408           0 :         int rv;
    1409           0 :         char *remark;
    1410           0 :         char xpath[XPATH_MAXLEN];
    1411             : 
    1412           0 :         snprintf(xpath, sizeof(xpath),
    1413             :                  "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
    1414           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
    1415             : 
    1416           0 :         remark = argv_concat(argv, argc, 4);
    1417           0 :         nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
    1418           0 :         rv = nb_cli_apply_changes(vty, "%s", xpath);
    1419           0 :         XFREE(MTYPE_TMP, remark);
    1420             : 
    1421           0 :         return rv;
    1422             : }
    1423             : 
    1424           0 : DEFPY_YANG(
    1425             :         no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd,
    1426             :         "no ip prefix-list WORD$name description",
    1427             :         NO_STR
    1428             :         IP_STR
    1429             :         PREFIX_LIST_STR
    1430             :         PREFIX_LIST_NAME_STR
    1431             :         ACCESS_LIST_REMARK_STR)
    1432             : {
    1433           0 :         char xpath[XPATH_MAXLEN];
    1434           0 :         int rv;
    1435             : 
    1436           0 :         snprintf(xpath, sizeof(xpath),
    1437             :                  "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
    1438             :                  name);
    1439           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1440             : 
    1441           0 :         rv = nb_cli_apply_changes(vty, NULL);
    1442           0 :         if (rv == CMD_SUCCESS)
    1443           0 :                 return plist_remove_if_empty(vty, "ipv4", name);
    1444             : 
    1445             :         return rv;
    1446             : }
    1447             : 
    1448             : ALIAS(
    1449             :         no_ip_prefix_list_remark, no_ip_prefix_list_remark_line_cmd,
    1450             :         "no ip prefix-list WORD$name description LINE...",
    1451             :         NO_STR
    1452             :         IP_STR
    1453             :         PREFIX_LIST_STR
    1454             :         PREFIX_LIST_NAME_STR
    1455             :         ACCESS_LIST_REMARK_STR
    1456             :         ACCESS_LIST_REMARK_LINE_STR)
    1457             : 
    1458           6 : DEFPY_YANG(
    1459             :         ipv6_prefix_list, ipv6_prefix_list_cmd,
    1460             :         "ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
    1461             :         IPV6_STR
    1462             :         PREFIX_LIST_STR
    1463             :         PREFIX_LIST_NAME_STR
    1464             :         ACCESS_LIST_SEQ_STR
    1465             :         ACCESS_LIST_ACTION_STR
    1466             :         "Any prefix match.  Same as \"::0/0 le 128\"\n"
    1467             :         "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
    1468             :         "Maximum prefix length to be matched\n"
    1469             :         "Maximum prefix length\n"
    1470             :         "Minimum prefix length to be matched\n"
    1471             :         "Minimum prefix length\n")
    1472             : {
    1473           6 :         int64_t sseq;
    1474           6 :         struct plist_dup_args pda = {};
    1475           6 :         char xpath[XPATH_MAXLEN];
    1476           6 :         char xpath_entry[XPATH_MAXLEN + 128];
    1477             : 
    1478             :         /*
    1479             :          * Backward compatibility: don't complain about duplicated values,
    1480             :          * just silently accept.
    1481             :          */
    1482           6 :         pda.pda_type = "ipv6";
    1483           6 :         pda.pda_name = name;
    1484           6 :         pda.pda_action = action;
    1485           6 :         if (prefix_str) {
    1486           6 :                 prefix_copy(&pda.prefix, prefix);
    1487           6 :                 pda.ge = ge;
    1488           6 :                 pda.le = le;
    1489             :         } else {
    1490           0 :                 pda.any = true;
    1491             :         }
    1492             : 
    1493           6 :         if (plist_is_dup(vty->candidate_config->dnode, &pda))
    1494             :                 return CMD_SUCCESS;
    1495             : 
    1496             :         /*
    1497             :          * Create the prefix-list first, so we can generate sequence if
    1498             :          * none given (backward compatibility).
    1499             :          */
    1500           6 :         snprintf(xpath, sizeof(xpath),
    1501             :                  "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
    1502           6 :         if (seq_str == NULL) {
    1503             :                 /* Use XPath to find the next sequence number. */
    1504           6 :                 sseq = acl_get_seq(vty, xpath, false);
    1505           6 :                 if (sseq < 0)
    1506             :                         return CMD_WARNING_CONFIG_FAILED;
    1507             : 
    1508           6 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
    1509             :                            "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
    1510             :         } else
    1511           0 :                 snprintfrr(xpath_entry, sizeof(xpath_entry),
    1512             :                            "%s/entry[sequence='%s']", xpath, seq_str);
    1513             : 
    1514           6 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
    1515           6 :         nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
    1516             : 
    1517           6 :         nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
    1518           6 :         if (prefix_str != NULL) {
    1519           6 :                 nb_cli_enqueue_change(vty, "./ipv6-prefix", NB_OP_MODIFY,
    1520             :                                       prefix_str);
    1521             : 
    1522           6 :                 if (ge_str) {
    1523           0 :                         nb_cli_enqueue_change(
    1524             :                                 vty, "./ipv6-prefix-length-greater-or-equal",
    1525             :                                 NB_OP_MODIFY, ge_str);
    1526             :                 } else {
    1527             :                         /*
    1528             :                          * Remove old ge if not being modified
    1529             :                          */
    1530           6 :                         nb_cli_enqueue_change(
    1531             :                                 vty, "./ipv6-prefix-length-greater-or-equal",
    1532             :                                 NB_OP_DESTROY, NULL);
    1533             :                 }
    1534             : 
    1535           6 :                 if (le_str) {
    1536           1 :                         nb_cli_enqueue_change(
    1537             :                                 vty, "./ipv6-prefix-length-lesser-or-equal",
    1538             :                                 NB_OP_MODIFY, le_str);
    1539             :                 } else {
    1540             :                         /*
    1541             :                          * Remove old le if not being modified
    1542             :                          */
    1543           5 :                         nb_cli_enqueue_change(
    1544             :                                 vty, "./ipv6-prefix-length-lesser-or-equal",
    1545             :                                 NB_OP_DESTROY, NULL);
    1546             :                 }
    1547             :         } else {
    1548           0 :                 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
    1549             :         }
    1550             : 
    1551           6 :         return nb_cli_apply_changes(vty, "%s", xpath_entry);
    1552             : }
    1553             : 
    1554           0 : DEFPY_YANG(
    1555             :         no_ipv6_prefix_list, no_ipv6_prefix_list_cmd,
    1556             :         "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
    1557             :         NO_STR
    1558             :         IPV6_STR
    1559             :         PREFIX_LIST_STR
    1560             :         PREFIX_LIST_NAME_STR
    1561             :         ACCESS_LIST_SEQ_STR
    1562             :         ACCESS_LIST_ACTION_STR
    1563             :         "Any prefix match.  Same as \"::0/0 le 128\"\n"
    1564             :         "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
    1565             :         "Maximum prefix length to be matched\n"
    1566             :         "Maximum prefix length\n"
    1567             :         "Minimum prefix length to be matched\n"
    1568             :         "Minimum prefix length\n")
    1569             : {
    1570           0 :         return plist_remove(vty, "ipv6", name, seq_str, action,
    1571           0 :                             prefix_str ? prefix : NULL, ge, le);
    1572             : }
    1573             : 
    1574           0 : DEFPY_YANG(
    1575             :         no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd,
    1576             :         "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
    1577             :         NO_STR
    1578             :         IPV6_STR
    1579             :         PREFIX_LIST_STR
    1580             :         PREFIX_LIST_NAME_STR
    1581             :         ACCESS_LIST_SEQ_STR)
    1582             : {
    1583           0 :         return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0);
    1584             : }
    1585             : 
    1586           0 : DEFPY_YANG(
    1587             :         no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd,
    1588             :         "no ipv6 prefix-list WORD$name",
    1589             :         NO_STR
    1590             :         IPV6_STR
    1591             :         PREFIX_LIST_STR
    1592             :         PREFIX_LIST_NAME_STR)
    1593             : {
    1594           0 :         char xpath[XPATH_MAXLEN];
    1595             : 
    1596           0 :         snprintf(xpath, sizeof(xpath),
    1597             :                  "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
    1598           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1599             : 
    1600           0 :         return nb_cli_apply_changes(vty, NULL);
    1601             : }
    1602             : 
    1603           0 : DEFPY_YANG(
    1604             :         ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd,
    1605             :         "ipv6 prefix-list WORD$name description LINE...",
    1606             :         IPV6_STR
    1607             :         PREFIX_LIST_STR
    1608             :         PREFIX_LIST_NAME_STR
    1609             :         ACCESS_LIST_REMARK_STR
    1610             :         ACCESS_LIST_REMARK_LINE_STR)
    1611             : {
    1612           0 :         int rv;
    1613           0 :         char *remark;
    1614           0 :         char xpath[XPATH_MAXLEN];
    1615             : 
    1616           0 :         snprintf(xpath, sizeof(xpath),
    1617             :                  "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
    1618           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
    1619             : 
    1620           0 :         remark = argv_concat(argv, argc, 4);
    1621           0 :         nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
    1622           0 :         rv = nb_cli_apply_changes(vty, "%s", xpath);
    1623           0 :         XFREE(MTYPE_TMP, remark);
    1624             : 
    1625           0 :         return rv;
    1626             : }
    1627             : 
    1628           0 : DEFPY_YANG(
    1629             :         no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd,
    1630             :         "no ipv6 prefix-list WORD$name description",
    1631             :         NO_STR
    1632             :         IPV6_STR
    1633             :         PREFIX_LIST_STR
    1634             :         PREFIX_LIST_NAME_STR
    1635             :         ACCESS_LIST_REMARK_STR)
    1636             : {
    1637           0 :         char xpath[XPATH_MAXLEN];
    1638           0 :         int rv;
    1639             : 
    1640           0 :         snprintf(xpath, sizeof(xpath),
    1641             :                  "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
    1642             :                  name);
    1643           0 :         nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
    1644             : 
    1645           0 :         rv = nb_cli_apply_changes(vty, NULL);
    1646           0 :         if (rv == CMD_SUCCESS)
    1647           0 :                 return plist_remove_if_empty(vty, "ipv6", name);
    1648             : 
    1649             :         return rv;
    1650             : }
    1651             : 
    1652             : ALIAS(
    1653             :         no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_line_cmd,
    1654             :         "no ipv6 prefix-list WORD$name description LINE...",
    1655             :         NO_STR
    1656             :         IPV6_STR
    1657             :         PREFIX_LIST_STR
    1658             :         PREFIX_LIST_NAME_STR
    1659             :         ACCESS_LIST_REMARK_STR
    1660             :         ACCESS_LIST_REMARK_LINE_STR)
    1661             : 
    1662           0 : int prefix_list_cmp(const struct lyd_node *dnode1,
    1663             :                     const struct lyd_node *dnode2)
    1664             : {
    1665           0 :         uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
    1666           0 :         uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
    1667             : 
    1668           0 :         return seq1 - seq2;
    1669             : }
    1670             : 
    1671           0 : void prefix_list_show(struct vty *vty, const struct lyd_node *dnode,
    1672             :                       bool show_defaults)
    1673             : {
    1674           0 :         int type = yang_dnode_get_enum(dnode, "../type");
    1675           0 :         const char *ge_str = NULL, *le_str = NULL;
    1676           0 :         bool is_any;
    1677           0 :         struct prefix p;
    1678             : 
    1679           0 :         is_any = yang_dnode_exists(dnode, "./any");
    1680           0 :         switch (type) {
    1681           0 :         case YPLT_IPV4:
    1682           0 :                 if (!is_any)
    1683           0 :                         yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
    1684           0 :                 if (yang_dnode_exists(dnode,
    1685             :                                       "./ipv4-prefix-length-greater-or-equal"))
    1686           0 :                         ge_str = yang_dnode_get_string(
    1687             :                                 dnode, "./ipv4-prefix-length-greater-or-equal");
    1688           0 :                 if (yang_dnode_exists(dnode,
    1689             :                                       "./ipv4-prefix-length-lesser-or-equal"))
    1690           0 :                         le_str = yang_dnode_get_string(
    1691             :                                 dnode, "./ipv4-prefix-length-lesser-or-equal");
    1692             : 
    1693           0 :                 vty_out(vty, "ip ");
    1694           0 :                 break;
    1695           0 :         case YPLT_IPV6:
    1696           0 :                 if (!is_any)
    1697           0 :                         yang_dnode_get_prefix(&p, dnode, "ipv6-prefix");
    1698           0 :                 if (yang_dnode_exists(dnode,
    1699             :                                       "./ipv6-prefix-length-greater-or-equal"))
    1700           0 :                         ge_str = yang_dnode_get_string(
    1701             :                                 dnode, "./ipv6-prefix-length-greater-or-equal");
    1702           0 :                 if (yang_dnode_exists(dnode,
    1703             :                                       "./ipv6-prefix-length-lesser-or-equal"))
    1704           0 :                         le_str = yang_dnode_get_string(
    1705             :                                 dnode, "./ipv6-prefix-length-lesser-or-equal");
    1706             : 
    1707           0 :                 vty_out(vty, "ipv6 ");
    1708           0 :                 break;
    1709             :         }
    1710             : 
    1711           0 :         vty_out(vty, "prefix-list %s seq %s %s",
    1712             :                 yang_dnode_get_string(dnode, "../name"),
    1713             :                 yang_dnode_get_string(dnode, "./sequence"),
    1714             :                 yang_dnode_get_string(dnode, "./action"));
    1715             : 
    1716           0 :         if (is_any) {
    1717           0 :                 vty_out(vty, " any\n");
    1718           0 :                 return;
    1719             :         }
    1720             : 
    1721           0 :         vty_out(vty, " %pFX", &p);
    1722           0 :         if (ge_str)
    1723           0 :                 vty_out(vty, " ge %s", ge_str);
    1724           0 :         if (le_str)
    1725           0 :                 vty_out(vty, " le %s", le_str);
    1726             : 
    1727           0 :         vty_out(vty, "\n");
    1728             : }
    1729             : 
    1730           0 : void prefix_list_remark_show(struct vty *vty, const struct lyd_node *dnode,
    1731             :                              bool show_defaults)
    1732             : {
    1733           0 :         int type = yang_dnode_get_enum(dnode, "../type");
    1734             : 
    1735           0 :         switch (type) {
    1736           0 :         case YPLT_IPV4:
    1737           0 :                 vty_out(vty, "ip ");
    1738           0 :                 break;
    1739           0 :         case YPLT_IPV6:
    1740           0 :                 vty_out(vty, "ipv6 ");
    1741           0 :                 break;
    1742             :         }
    1743             : 
    1744           0 :         vty_out(vty, "prefix-list %s description %s\n",
    1745             :                 yang_dnode_get_string(dnode, "../name"),
    1746             :                 yang_dnode_get_string(dnode, NULL));
    1747           0 : }
    1748             : 
    1749         201 : void filter_cli_init(void)
    1750             : {
    1751             :         /* access-list cisco-style (legacy). */
    1752         201 :         install_element(CONFIG_NODE, &access_list_std_cmd);
    1753         201 :         install_element(CONFIG_NODE, &no_access_list_std_cmd);
    1754         201 :         install_element(CONFIG_NODE, &access_list_ext_cmd);
    1755         201 :         install_element(CONFIG_NODE, &no_access_list_ext_cmd);
    1756             : 
    1757             :         /* access-list zebra-style. */
    1758         201 :         install_element(CONFIG_NODE, &access_list_cmd);
    1759         201 :         install_element(CONFIG_NODE, &no_access_list_cmd);
    1760         201 :         install_element(CONFIG_NODE, &no_access_list_all_cmd);
    1761         201 :         install_element(CONFIG_NODE, &access_list_remark_cmd);
    1762         201 :         install_element(CONFIG_NODE, &no_access_list_remark_cmd);
    1763         201 :         install_element(CONFIG_NODE, &no_access_list_remark_line_cmd);
    1764             : 
    1765         201 :         install_element(CONFIG_NODE, &ipv6_access_list_cmd);
    1766         201 :         install_element(CONFIG_NODE, &no_ipv6_access_list_cmd);
    1767         201 :         install_element(CONFIG_NODE, &no_ipv6_access_list_all_cmd);
    1768         201 :         install_element(CONFIG_NODE, &ipv6_access_list_remark_cmd);
    1769         201 :         install_element(CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
    1770         201 :         install_element(CONFIG_NODE, &no_ipv6_access_list_remark_line_cmd);
    1771             : 
    1772         201 :         install_element(CONFIG_NODE, &mac_access_list_cmd);
    1773         201 :         install_element(CONFIG_NODE, &no_mac_access_list_cmd);
    1774         201 :         install_element(CONFIG_NODE, &no_mac_access_list_all_cmd);
    1775         201 :         install_element(CONFIG_NODE, &mac_access_list_remark_cmd);
    1776         201 :         install_element(CONFIG_NODE, &no_mac_access_list_remark_cmd);
    1777         201 :         install_element(CONFIG_NODE, &no_mac_access_list_remark_line_cmd);
    1778             : 
    1779             :         /* prefix lists. */
    1780         201 :         install_element(CONFIG_NODE, &ip_prefix_list_cmd);
    1781         201 :         install_element(CONFIG_NODE, &no_ip_prefix_list_cmd);
    1782         201 :         install_element(CONFIG_NODE, &no_ip_prefix_list_seq_cmd);
    1783         201 :         install_element(CONFIG_NODE, &no_ip_prefix_list_all_cmd);
    1784         201 :         install_element(CONFIG_NODE, &ip_prefix_list_remark_cmd);
    1785         201 :         install_element(CONFIG_NODE, &no_ip_prefix_list_remark_cmd);
    1786         201 :         install_element(CONFIG_NODE, &no_ip_prefix_list_remark_line_cmd);
    1787             : 
    1788         201 :         install_element(CONFIG_NODE, &ipv6_prefix_list_cmd);
    1789         201 :         install_element(CONFIG_NODE, &no_ipv6_prefix_list_cmd);
    1790         201 :         install_element(CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd);
    1791         201 :         install_element(CONFIG_NODE, &no_ipv6_prefix_list_all_cmd);
    1792         201 :         install_element(CONFIG_NODE, &ipv6_prefix_list_remark_cmd);
    1793         201 :         install_element(CONFIG_NODE, &no_ipv6_prefix_list_remark_cmd);
    1794         201 :         install_element(CONFIG_NODE, &no_ipv6_prefix_list_remark_line_cmd);
    1795         201 : }

Generated by: LCOV version v1.16-topotato