back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_pbr.c (source / functions) Hit Total Coverage
Test: test_exabgp_demo.py::ExaBGPDemo Lines: 13 722 1.8 %
Date: 2023-02-24 18:37:55 Functions: 6 70 8.6 %

          Line data    Source code
       1             : /* Zebra Policy Based Routing (PBR) main handling.
       2             :  * Copyright (C) 2018  Cumulus Networks, Inc.
       3             :  *
       4             :  * This file is part of FRR.
       5             :  *
       6             :  * FRR is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * FRR is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with FRR; see the file COPYING.  If not, write to the Free
      18             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      19             :  * 02111-1307, USA.
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include <jhash.h>
      25             : #include <hash.h>
      26             : #include <memory.h>
      27             : #include <hook.h>
      28             : 
      29             : #include "zebra/zebra_router.h"
      30             : #include "zebra/zebra_pbr.h"
      31             : #include "zebra/rt.h"
      32             : #include "zebra/zapi_msg.h"
      33             : #include "zebra/zserv.h"
      34             : #include "zebra/debug.h"
      35             : #include "zebra/zebra_neigh.h"
      36             : 
      37             : /* definitions */
      38           9 : DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
      39           9 : DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR");
      40             : 
      41             : /* definitions */
      42             : static const struct message ipset_type_msg[] = {
      43             :         {IPSET_NET_PORT_NET, "net,port,net"},
      44             :         {IPSET_NET_PORT, "net,port"},
      45             :         {IPSET_NET_NET, "net,net"},
      46             :         {IPSET_NET, "net"},
      47             :         {0}
      48             : };
      49             : 
      50             : const struct message icmp_typecode_str[] = {
      51             :         { 0 << 8, "echo-reply"},
      52             :         { 0 << 8, "pong"},
      53             :         { 3 << 8, "network-unreachable"},
      54             :         { (3 << 8) + 1, "host-unreachable"},
      55             :         { (3 << 8) + 2, "protocol-unreachable"},
      56             :         { (3 << 8) + 3, "port-unreachable"},
      57             :         { (3 << 8) + 4, "fragmentation-needed"},
      58             :         { (3 << 8) + 5, "source-route-failed"},
      59             :         { (3 << 8) + 6, "network-unknown"},
      60             :         { (3 << 8) + 7, "host-unknown"},
      61             :         { (3 << 8) + 9, "network-prohibited"},
      62             :         { (3 << 8) + 10, "host-prohibited"},
      63             :         { (3 << 8) + 11, "TOS-network-unreachable"},
      64             :         { (3 << 8) + 12, "TOS-host-unreachable"},
      65             :         { (3 << 8) + 13, "communication-prohibited"},
      66             :         { (3 << 8) + 14, "host-precedence-violation"},
      67             :         { (3 << 8) + 15, "precedence-cutoff"},
      68             :         { 4 << 8, "source-quench"},
      69             :         { 5 << 8, "network-redirect"},
      70             :         { (5 << 8) +  1, "host-redirect"},
      71             :         { (5 << 8) +  2, "TOS-network-redirect"},
      72             :         { (5 << 8) +  3, "TOS-host-redirect"},
      73             :         { 8 << 8, "echo-request"},
      74             :         { 8 << 8, "ping"},
      75             :         { 9 << 8, "router-advertisement"},
      76             :         { 10 << 8, "router-solicitation"},
      77             :         { 11 << 8, "ttl-zero-during-transit"},
      78             :         { (11 << 8) + 1, "ttl-zero-during-reassembly"},
      79             :         { 12 << 8, "ip-header-bad"},
      80             :         { (12 << 8) + 1, "required-option-missing"},
      81             :         { 13 << 8, "timestamp-request"},
      82             :         { 14 << 8, "timestamp-reply"},
      83             :         { 17 << 8, "address-mask-request"},
      84             :         { 18 << 8, "address-mask-reply"},
      85             :         {0}
      86             : };
      87             : 
      88             : const struct message icmpv6_typecode_str[] = {
      89             :         { 128 << 8, "echo-request"},
      90             :         { 129 << 8, "echo-reply"},
      91             :         { 1 << 8, "no-route"},
      92             :         { (1 << 8) + 1, "communication-prohibited"},
      93             :         { (1 << 8) + 3, "address-unreachable"},
      94             :         { (1 << 8) + 4, "port-unreachable"},
      95             :         { (2 << 8), "packet-too-big"},
      96             :         { 3 << 0, "ttl-zero-during-transit"},
      97             :         { (3 << 8) + 1, "ttl-zero-during-reassembly"},
      98             :         { 4 << 0, "bad-header"},
      99             :         { (4 << 0) + 1, "unknown-header-type"},
     100             :         { (4 << 0) + 2, "unknown-option"},
     101             :         { 133 << 8, "router-solicitation"},
     102             :         { 134 << 8, "router-advertisement"},
     103             :         { 135 << 8, "neighbor-solicitation"},
     104             :         { 136 << 8, "neighbor-advertisement"},
     105             :         { 137 << 8, "redirect"},
     106             :         {0}
     107             : };
     108             : 
     109             : /* definitions */
     110             : static const struct message tcp_value_str[] = {
     111             :         {TCP_HEADER_FIN, "FIN"},
     112             :         {TCP_HEADER_SYN, "SYN"},
     113             :         {TCP_HEADER_RST, "RST"},
     114             :         {TCP_HEADER_PSH, "PSH"},
     115             :         {TCP_HEADER_ACK, "ACK"},
     116             :         {TCP_HEADER_URG, "URG"},
     117             :         {0}
     118             : };
     119             : 
     120             : static const struct message fragment_value_str[] = {
     121             :         {1, "dont-fragment"},
     122             :         {2, "is-fragment"},
     123             :         {4, "first-fragment"},
     124             :         {8, "last-fragment"},
     125             :         {0}
     126             : };
     127             : 
     128             : struct zebra_pbr_env_display {
     129             :         struct zebra_ns *zns;
     130             :         struct vty *vty;
     131             :         char *name;
     132             : };
     133             : 
     134             : /* static function declarations */
     135           0 : DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
     136             :             (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
     137             :              uint64_t *bytes),
     138             :             (ipset, pkts, bytes));
     139             : 
     140           0 : DEFINE_HOOK(zebra_pbr_iptable_get_stat,
     141             :             (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
     142             :              uint64_t *bytes),
     143             :             (iptable, pkts, bytes));
     144             : 
     145           0 : DEFINE_HOOK(zebra_pbr_iptable_update,
     146             :             (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
     147             : 
     148           0 : DEFINE_HOOK(zebra_pbr_ipset_entry_update,
     149             :             (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset));
     150             : 
     151           0 : DEFINE_HOOK(zebra_pbr_ipset_update,
     152             :             (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
     153             : 
     154             : /* resolve nexthop for dataplane (dpdk) programming */
     155             : static bool zebra_pbr_expand_action;
     156             : 
     157             : /* Private functions */
     158             : 
     159             : /* Public functions */
     160           0 : void zebra_pbr_rules_free(void *arg)
     161             : {
     162           0 :         struct zebra_pbr_rule *rule;
     163             : 
     164           0 :         rule = (struct zebra_pbr_rule *)arg;
     165             : 
     166           0 :         (void)dplane_pbr_rule_delete(rule);
     167           0 :         XFREE(MTYPE_PBR_OBJ, rule);
     168           0 : }
     169             : 
     170           0 : uint32_t zebra_pbr_rules_hash_key(const void *arg)
     171             : {
     172           0 :         const struct zebra_pbr_rule *rule;
     173           0 :         uint32_t key;
     174             : 
     175           0 :         rule = arg;
     176           0 :         key = jhash_3words(rule->rule.seq, rule->rule.priority,
     177           0 :                            rule->rule.action.table,
     178           0 :                            prefix_hash_key(&rule->rule.filter.src_ip));
     179             : 
     180           0 :         key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
     181           0 :                            rule->rule.filter.ip_proto, key);
     182             : 
     183           0 :         key = jhash(rule->ifname, strlen(rule->ifname), key);
     184             : 
     185           0 :         return jhash_3words(rule->rule.filter.src_port,
     186           0 :                             rule->rule.filter.dst_port,
     187           0 :                             prefix_hash_key(&rule->rule.filter.dst_ip),
     188           0 :                             jhash_1word(rule->rule.unique, key));
     189             : }
     190             : 
     191           0 : bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
     192             : {
     193           0 :         const struct zebra_pbr_rule *r1, *r2;
     194             : 
     195           0 :         r1 = (const struct zebra_pbr_rule *)arg1;
     196           0 :         r2 = (const struct zebra_pbr_rule *)arg2;
     197             : 
     198           0 :         if (r1->rule.seq != r2->rule.seq)
     199             :                 return false;
     200             : 
     201           0 :         if (r1->rule.priority != r2->rule.priority)
     202             :                 return false;
     203             : 
     204           0 :         if (r1->rule.unique != r2->rule.unique)
     205             :                 return false;
     206             : 
     207           0 :         if (r1->rule.action.table != r2->rule.action.table)
     208             :                 return false;
     209             : 
     210           0 :         if (r1->rule.filter.src_port != r2->rule.filter.src_port)
     211             :                 return false;
     212             : 
     213           0 :         if (r1->rule.filter.dst_port != r2->rule.filter.dst_port)
     214             :                 return false;
     215             : 
     216           0 :         if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)
     217             :                 return false;
     218             : 
     219           0 :         if (r1->rule.filter.ip_proto != r2->rule.filter.ip_proto)
     220             :                 return false;
     221             : 
     222           0 :         if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))
     223             :                 return false;
     224             : 
     225           0 :         if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
     226             :                 return false;
     227             : 
     228           0 :         if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0)
     229             :                 return false;
     230             : 
     231           0 :         if (r1->vrf_id != r2->vrf_id)
     232             :                 return false;
     233             : 
     234             :         return true;
     235             : }
     236             : 
     237             : struct pbr_rule_unique_lookup {
     238             :         struct zebra_pbr_rule *rule;
     239             :         uint32_t unique;
     240             :         char ifname[INTERFACE_NAMSIZ + 1];
     241             :         vrf_id_t vrf_id;
     242             : };
     243             : 
     244           0 : static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
     245             : {
     246           0 :         struct pbr_rule_unique_lookup *pul = data;
     247           0 :         struct zebra_pbr_rule *rule = b->data;
     248             : 
     249           0 :         if (pul->unique == rule->rule.unique
     250           0 :             && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0
     251           0 :             && pul->vrf_id == rule->vrf_id) {
     252           0 :                 pul->rule = rule;
     253           0 :                 return HASHWALK_ABORT;
     254             :         }
     255             : 
     256             :         return HASHWALK_CONTINUE;
     257             : }
     258             : 
     259             : static struct zebra_pbr_rule *
     260           0 : pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
     261             : {
     262           0 :         struct pbr_rule_unique_lookup pul;
     263             : 
     264           0 :         pul.unique = zrule->rule.unique;
     265           0 :         strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ);
     266           0 :         pul.rule = NULL;
     267           0 :         pul.vrf_id = zrule->vrf_id;
     268           0 :         hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
     269             : 
     270           0 :         return pul.rule;
     271             : }
     272             : 
     273           0 : void zebra_pbr_ipset_free(void *arg)
     274             : {
     275           0 :         struct zebra_pbr_ipset *ipset;
     276             : 
     277           0 :         ipset = (struct zebra_pbr_ipset *)arg;
     278           0 :         hook_call(zebra_pbr_ipset_update, 0, ipset);
     279           0 :         XFREE(MTYPE_PBR_OBJ, ipset);
     280           0 : }
     281             : 
     282           0 : uint32_t zebra_pbr_ipset_hash_key(const void *arg)
     283             : {
     284           0 :         const struct zebra_pbr_ipset *ipset = arg;
     285           0 :         uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
     286           0 :         uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de);
     287             : 
     288           0 :         key =  jhash_1word(ipset->family, key);
     289             : 
     290           0 :         return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key);
     291             : }
     292             : 
     293           0 : bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2)
     294             : {
     295           0 :         const struct zebra_pbr_ipset *r1, *r2;
     296             : 
     297           0 :         r1 = (const struct zebra_pbr_ipset *)arg1;
     298           0 :         r2 = (const struct zebra_pbr_ipset *)arg2;
     299             : 
     300           0 :         if (r1->type != r2->type)
     301             :                 return false;
     302           0 :         if (r1->unique != r2->unique)
     303             :                 return false;
     304           0 :         if (r1->vrf_id != r2->vrf_id)
     305             :                 return false;
     306           0 :         if (r1->family != r2->family)
     307             :                 return false;
     308             : 
     309           0 :         if (strncmp(r1->ipset_name, r2->ipset_name,
     310             :                     ZEBRA_IPSET_NAME_SIZE))
     311           0 :                 return false;
     312             :         return true;
     313             : }
     314             : 
     315           0 : void zebra_pbr_ipset_entry_free(void *arg)
     316             : {
     317           0 :         struct zebra_pbr_ipset_entry *ipset;
     318             : 
     319           0 :         ipset = (struct zebra_pbr_ipset_entry *)arg;
     320             : 
     321           0 :         hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
     322             : 
     323           0 :         XFREE(MTYPE_PBR_OBJ, ipset);
     324           0 : }
     325             : 
     326           0 : uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
     327             : {
     328           0 :         const struct zebra_pbr_ipset_entry *ipset;
     329           0 :         uint32_t key;
     330             : 
     331           0 :         ipset = arg;
     332           0 :         key = prefix_hash_key(&ipset->src);
     333           0 :         key = jhash_1word(ipset->unique, key);
     334           0 :         key = jhash_1word(prefix_hash_key(&ipset->dst), key);
     335           0 :         key = jhash(&ipset->dst_port_min, 2, key);
     336           0 :         key = jhash(&ipset->dst_port_max, 2, key);
     337           0 :         key = jhash(&ipset->src_port_min, 2, key);
     338           0 :         key = jhash(&ipset->src_port_max, 2, key);
     339           0 :         key = jhash(&ipset->proto, 1, key);
     340             : 
     341           0 :         return key;
     342             : }
     343             : 
     344           0 : bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2)
     345             : {
     346           0 :         const struct zebra_pbr_ipset_entry *r1, *r2;
     347             : 
     348           0 :         r1 = (const struct zebra_pbr_ipset_entry *)arg1;
     349           0 :         r2 = (const struct zebra_pbr_ipset_entry *)arg2;
     350             : 
     351           0 :         if (r1->unique != r2->unique)
     352             :                 return false;
     353             : 
     354           0 :         if (!prefix_same(&r1->src, &r2->src))
     355             :                 return false;
     356             : 
     357           0 :         if (!prefix_same(&r1->dst, &r2->dst))
     358             :                 return false;
     359             : 
     360           0 :         if (r1->src_port_min != r2->src_port_min)
     361             :                 return false;
     362             : 
     363           0 :         if (r1->src_port_max != r2->src_port_max)
     364             :                 return false;
     365             : 
     366           0 :         if (r1->dst_port_min != r2->dst_port_min)
     367             :                 return false;
     368             : 
     369           0 :         if (r1->dst_port_max != r2->dst_port_max)
     370             :                 return false;
     371             : 
     372           0 :         if (r1->proto != r2->proto)
     373             :                 return false;
     374             :         return true;
     375             : }
     376             : 
     377             : /* this function gives option to flush plugin memory contexts
     378             :  * with all parameter. set it to true to flush all
     379             :  * set it to false to flush only passed arg argument
     380             :  */
     381           0 : static void _zebra_pbr_iptable_free_all(void *arg, bool all)
     382             : {
     383           0 :         struct zebra_pbr_iptable *iptable;
     384           0 :         struct listnode *node, *nnode;
     385           0 :         char *name;
     386             : 
     387           0 :         iptable = (struct zebra_pbr_iptable *)arg;
     388             : 
     389           0 :         if (all)
     390           0 :                 hook_call(zebra_pbr_iptable_update, 0, iptable);
     391             : 
     392           0 :         if (iptable->interface_name_list) {
     393           0 :                 for (ALL_LIST_ELEMENTS(iptable->interface_name_list, node,
     394             :                                        nnode, name)) {
     395           0 :                         XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
     396           0 :                         list_delete_node(iptable->interface_name_list, node);
     397             :                 }
     398           0 :                 list_delete(&iptable->interface_name_list);
     399             :         }
     400           0 :         XFREE(MTYPE_PBR_OBJ, iptable);
     401           0 : }
     402             : 
     403           0 : void zebra_pbr_iptable_free(void *arg)
     404             : {
     405           0 :         _zebra_pbr_iptable_free_all(arg, false);
     406           0 : }
     407             : 
     408           0 : uint32_t zebra_pbr_iptable_hash_key(const void *arg)
     409             : {
     410           0 :         const struct zebra_pbr_iptable *iptable = arg;
     411           0 :         uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
     412           0 :         uint32_t key;
     413             : 
     414           0 :         key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE,
     415             :                      0x63ab42de);
     416           0 :         key = jhash_1word(iptable->fwmark, key);
     417           0 :         key = jhash_1word(iptable->family, key);
     418           0 :         key = jhash_1word(iptable->flow_label, key);
     419           0 :         key = jhash_1word(iptable->pkt_len_min, key);
     420           0 :         key = jhash_1word(iptable->pkt_len_max, key);
     421           0 :         key = jhash_1word(iptable->tcp_flags, key);
     422           0 :         key = jhash_1word(iptable->tcp_mask_flags, key);
     423           0 :         key = jhash_1word(iptable->dscp_value, key);
     424           0 :         key = jhash_1word(iptable->protocol, key);
     425           0 :         key = jhash_1word(iptable->fragment, key);
     426           0 :         key = jhash_1word(iptable->vrf_id, key);
     427             : 
     428           0 :         return jhash_3words(iptable->filter_bm, iptable->type,
     429           0 :                             iptable->unique, key);
     430             : }
     431             : 
     432           0 : bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2)
     433             : {
     434           0 :         const struct zebra_pbr_iptable *r1, *r2;
     435             : 
     436           0 :         r1 = (const struct zebra_pbr_iptable *)arg1;
     437           0 :         r2 = (const struct zebra_pbr_iptable *)arg2;
     438             : 
     439           0 :         if (r1->vrf_id != r2->vrf_id)
     440             :                 return false;
     441           0 :         if (r1->type != r2->type)
     442             :                 return false;
     443           0 :         if (r1->unique != r2->unique)
     444             :                 return false;
     445           0 :         if (r1->filter_bm != r2->filter_bm)
     446             :                 return false;
     447           0 :         if (r1->fwmark != r2->fwmark)
     448             :                 return false;
     449           0 :         if (r1->action != r2->action)
     450             :                 return false;
     451           0 :         if (strncmp(r1->ipset_name, r2->ipset_name,
     452             :                     ZEBRA_IPSET_NAME_SIZE))
     453             :                 return false;
     454           0 :         if (r1->family != r2->family)
     455             :                 return false;
     456           0 :         if (r1->flow_label != r2->flow_label)
     457             :                 return false;
     458           0 :         if (r1->pkt_len_min != r2->pkt_len_min)
     459             :                 return false;
     460           0 :         if (r1->pkt_len_max != r2->pkt_len_max)
     461             :                 return false;
     462           0 :         if (r1->tcp_flags != r2->tcp_flags)
     463             :                 return false;
     464           0 :         if (r1->tcp_mask_flags != r2->tcp_mask_flags)
     465             :                 return false;
     466           0 :         if (r1->dscp_value != r2->dscp_value)
     467             :                 return false;
     468           0 :         if (r1->fragment != r2->fragment)
     469             :                 return false;
     470           0 :         if (r1->protocol != r2->protocol)
     471           0 :                 return false;
     472             :         return true;
     473             : }
     474             : 
     475           0 : static void *pbr_rule_alloc_intern(void *arg)
     476             : {
     477           0 :         struct zebra_pbr_rule *zpr;
     478           0 :         struct zebra_pbr_rule *new;
     479             : 
     480           0 :         zpr = (struct zebra_pbr_rule *)arg;
     481             : 
     482           0 :         new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new));
     483             : 
     484           0 :         memcpy(new, zpr, sizeof(*zpr));
     485             : 
     486           0 :         return new;
     487             : }
     488             : 
     489           0 : static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data,
     490             :                                             bool free_data)
     491             : {
     492           0 :         if (hash_data->action.neigh)
     493           0 :                 zebra_neigh_deref(hash_data);
     494           0 :         hash_release(zrouter.rules_hash, hash_data);
     495           0 :         if (free_data) {
     496           0 :                 XFREE(MTYPE_PBR_OBJ, hash_data);
     497           0 :                 return NULL;
     498             :         }
     499             : 
     500             :         return hash_data;
     501             : }
     502             : 
     503           0 : static struct zebra_pbr_rule *pbr_rule_release(struct zebra_pbr_rule *rule,
     504             :                                                bool free_data)
     505             : {
     506           0 :         struct zebra_pbr_rule *lookup;
     507             : 
     508           0 :         lookup = hash_lookup(zrouter.rules_hash, rule);
     509             : 
     510           0 :         if (!lookup)
     511             :                 return NULL;
     512             : 
     513           0 :         return pbr_rule_free(lookup, free_data);
     514             : }
     515             : 
     516           0 : void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty)
     517             : {
     518           0 :         struct pbr_rule *prule = &rule->rule;
     519           0 :         struct zebra_pbr_action *zaction = &rule->action;
     520             : 
     521           0 :         vty_out(vty, "Rules if %s\n", rule->ifname);
     522           0 :         vty_out(vty, "  Seq %u pri %u\n", prule->seq, prule->priority);
     523           0 :         if (prule->filter.filter_bm & PBR_FILTER_SRC_IP)
     524           0 :                 vty_out(vty, "  SRC IP Match: %pFX\n", &prule->filter.src_ip);
     525           0 :         if (prule->filter.filter_bm & PBR_FILTER_DST_IP)
     526           0 :                 vty_out(vty, "  DST IP Match: %pFX\n", &prule->filter.dst_ip);
     527           0 :         if (prule->filter.filter_bm & PBR_FILTER_IP_PROTOCOL)
     528           0 :                 vty_out(vty, "  IP protocol Match: %u\n",
     529           0 :                         prule->filter.ip_proto);
     530           0 :         if (prule->filter.filter_bm & PBR_FILTER_SRC_PORT)
     531           0 :                 vty_out(vty, "  SRC Port Match: %u\n", prule->filter.src_port);
     532           0 :         if (prule->filter.filter_bm & PBR_FILTER_DST_PORT)
     533           0 :                 vty_out(vty, "  DST Port Match: %u\n", prule->filter.dst_port);
     534             : 
     535           0 :         if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) {
     536           0 :                 vty_out(vty, "  DSCP Match: %u\n",
     537           0 :                         (prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2);
     538           0 :                 vty_out(vty, "  ECN Match: %u\n",
     539           0 :                         prule->filter.dsfield & PBR_DSFIELD_ECN);
     540             :         }
     541             : 
     542           0 :         if (prule->filter.filter_bm & PBR_FILTER_FWMARK)
     543           0 :                 vty_out(vty, "  MARK Match: %u\n", prule->filter.fwmark);
     544             : 
     545           0 :         vty_out(vty, "  Tableid: %u\n", prule->action.table);
     546           0 :         if (zaction->afi == AFI_IP)
     547           0 :                 vty_out(vty, "  Action: nh: %pI4 intf: %s\n",
     548             :                         &zaction->gate.ipv4,
     549             :                         ifindex2ifname(zaction->ifindex, rule->vrf_id));
     550           0 :         if (zaction->afi == AFI_IP6)
     551           0 :                 vty_out(vty, "  Action: nh: %pI6 intf: %s\n",
     552             :                         &zaction->gate.ipv6,
     553             :                         ifindex2ifname(zaction->ifindex, rule->vrf_id));
     554           0 :         if (zaction->neigh && (zaction->neigh->flags & ZEBRA_NEIGH_ENT_ACTIVE))
     555           0 :                 vty_out(vty, "  Action: mac: %pEA\n", &zaction->neigh->mac);
     556           0 : }
     557             : 
     558           0 : static int zebra_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
     559             : {
     560           0 :         struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data;
     561           0 :         struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
     562           0 :         struct vty *vty = env->vty;
     563             : 
     564           0 :         zebra_pbr_show_rule_unit(rule, vty);
     565             : 
     566           0 :         return HASHWALK_CONTINUE;
     567             : }
     568             : 
     569           0 : void zebra_pbr_show_rule(struct vty *vty)
     570             : {
     571           0 :         struct zebra_pbr_env_display env;
     572             : 
     573           0 :         env.vty = vty;
     574           0 :         hash_walk(zrouter.rules_hash, zebra_pbr_show_rules_walkcb, &env);
     575           0 : }
     576             : 
     577           0 : void zebra_pbr_config_write(struct vty *vty)
     578             : {
     579           0 :         if (zebra_pbr_expand_action)
     580           0 :                 vty_out(vty, "pbr nexthop-resolve\n");
     581           0 : }
     582             : 
     583           0 : void zebra_pbr_expand_action_update(bool enable)
     584             : {
     585           0 :         zebra_pbr_expand_action = enable;
     586           0 : }
     587             : 
     588           0 : static void zebra_pbr_expand_rule(struct zebra_pbr_rule *rule)
     589             : {
     590           0 :         struct prefix p;
     591           0 :         struct route_table *table;
     592           0 :         struct route_node *rn;
     593           0 :         rib_dest_t *dest;
     594           0 :         struct route_entry *re;
     595           0 :         const struct nexthop_group *nhg;
     596           0 :         const struct nexthop *nexthop;
     597           0 :         struct zebra_pbr_action *action = &rule->action;
     598           0 :         struct ipaddr ip;
     599             : 
     600           0 :         if (!zebra_pbr_expand_action)
     601           0 :                 return;
     602             : 
     603           0 :         table = zebra_vrf_get_table_with_table_id(
     604             :                 AFI_IP, SAFI_UNICAST, VRF_DEFAULT, rule->rule.action.table);
     605           0 :         if (!table)
     606             :                 return;
     607             : 
     608           0 :         memset(&p, 0, sizeof(p));
     609           0 :         p.family = AF_INET;
     610             : 
     611           0 :         rn = route_node_lookup(table, &p);
     612           0 :         if (!rn)
     613             :                 return;
     614             : 
     615           0 :         dest = rib_dest_from_rnode(rn);
     616           0 :         re = dest->selected_fib;
     617           0 :         if (!re) {
     618           0 :                 route_unlock_node(rn);
     619           0 :                 return;
     620             :         }
     621             : 
     622           0 :         nhg = rib_get_fib_nhg(re);
     623           0 :         if (!nhg) {
     624             :                 route_unlock_node(rn);
     625             :                 return;
     626             :         }
     627             : 
     628           0 :         nexthop = nhg->nexthop;
     629           0 :         if (nexthop) {
     630           0 :                 switch (nexthop->type) {
     631           0 :                 case NEXTHOP_TYPE_IPV4:
     632             :                 case NEXTHOP_TYPE_IPV4_IFINDEX:
     633           0 :                         action->afi = AFI_IP;
     634           0 :                         action->gate.ipv4 = nexthop->gate.ipv4;
     635           0 :                         action->ifindex = nexthop->ifindex;
     636           0 :                         ip.ipa_type = AF_INET;
     637           0 :                         ip.ipaddr_v4 = action->gate.ipv4;
     638           0 :                         zebra_neigh_ref(action->ifindex, &ip, rule);
     639           0 :                         break;
     640             : 
     641           0 :                 case NEXTHOP_TYPE_IPV6:
     642             :                 case NEXTHOP_TYPE_IPV6_IFINDEX:
     643           0 :                         action->afi = AFI_IP6;
     644           0 :                         action->gate.ipv6 = nexthop->gate.ipv6;
     645           0 :                         action->ifindex = nexthop->ifindex;
     646           0 :                         ip.ipa_type = AF_INET6;
     647           0 :                         ip.ipaddr_v6 = action->gate.ipv6;
     648           0 :                         zebra_neigh_ref(action->ifindex, &ip, rule);
     649           0 :                         break;
     650             : 
     651           0 :                 case NEXTHOP_TYPE_BLACKHOLE:
     652             :                 case NEXTHOP_TYPE_IFINDEX:
     653           0 :                         action->afi = AFI_UNSPEC;
     654             :                 }
     655             :         }
     656             : 
     657           0 :         route_unlock_node(rn);
     658             : }
     659             : 
     660           0 : void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
     661             : {
     662           0 :         struct zebra_pbr_rule *found;
     663           0 :         struct zebra_pbr_rule *old;
     664           0 :         struct zebra_pbr_rule *new;
     665             : 
     666             :         /**
     667             :          * Check if we already have it (this checks via a unique ID, walking
     668             :          * over the hash table, not via a hash operation).
     669             :          */
     670           0 :         found = pbr_rule_lookup_unique(rule);
     671             : 
     672             :         /* If found, this is an update */
     673           0 :         if (found) {
     674           0 :                 if (IS_ZEBRA_DEBUG_PBR)
     675           0 :                         zlog_debug(
     676             :                                 "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- update",
     677             :                                 __func__, rule->rule.seq, rule->rule.priority,
     678             :                                 rule->rule.unique, rule->rule.ifname);
     679             : 
     680             :                 /* remove the old entry from the hash but don't free the hash
     681             :                  * data yet as we need it for the dplane update
     682             :                  */
     683           0 :                 old = pbr_rule_release(found, false);
     684             : 
     685             :                 /* insert new entry into hash */
     686           0 :                 new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
     687             :                 /* expand the action if needed */
     688           0 :                 zebra_pbr_expand_rule(new);
     689             :                 /* update dataplane */
     690           0 :                 (void)dplane_pbr_rule_update(found, new);
     691             :                 /* release the old hash data */
     692           0 :                 if (old)
     693           0 :                         XFREE(MTYPE_PBR_OBJ, old);
     694             :         } else {
     695           0 :                 if (IS_ZEBRA_DEBUG_PBR)
     696           0 :                         zlog_debug(
     697             :                                 "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- new",
     698             :                                 __func__, rule->rule.seq, rule->rule.priority,
     699             :                                 rule->rule.unique, rule->rule.ifname);
     700             : 
     701             :                 /* insert new entry into hash */
     702           0 :                 new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
     703             :                 /* expand the action if needed */
     704           0 :                 zebra_pbr_expand_rule(new);
     705           0 :                 (void)dplane_pbr_rule_add(new);
     706             :         }
     707             : 
     708           0 : }
     709             : 
     710           0 : void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
     711             : {
     712           0 :         if (IS_ZEBRA_DEBUG_PBR)
     713           0 :                 zlog_debug("%s: seq: %d, prior: %d, unique: %d, ifname: %s",
     714             :                            __func__, rule->rule.seq, rule->rule.priority,
     715             :                            rule->rule.unique, rule->rule.ifname);
     716             : 
     717           0 :         (void)dplane_pbr_rule_delete(rule);
     718             : 
     719           0 :         if (pbr_rule_release(rule, true))
     720           0 :                 zlog_debug("%s: Rule being deleted we know nothing about",
     721             :                            __func__);
     722           0 : }
     723             : 
     724           0 : void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx)
     725             : {
     726           0 :         int mode, ret = 0;
     727           0 :         struct zebra_pbr_iptable ipt;
     728             : 
     729           0 :         if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD)
     730             :                 mode = 1;
     731             :         else
     732           0 :                 mode = 0;
     733             : 
     734           0 :         dplane_ctx_get_pbr_iptable(ctx, &ipt);
     735             : 
     736           0 :         ret = hook_call(zebra_pbr_iptable_update, mode, &ipt);
     737           0 :         if (ret)
     738           0 :                 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
     739             :         else
     740           0 :                 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
     741           0 : }
     742             : 
     743           0 : void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx)
     744             : {
     745           0 :         int mode, ret = 0;
     746           0 :         struct zebra_pbr_ipset ipset;
     747             : 
     748           0 :         if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD)
     749             :                 mode = 1;
     750             :         else
     751           0 :                 mode = 0;
     752             : 
     753           0 :         dplane_ctx_get_pbr_ipset(ctx, &ipset);
     754             : 
     755           0 :         ret = hook_call(zebra_pbr_ipset_update, mode, &ipset);
     756           0 :         if (ret)
     757           0 :                 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
     758             :         else
     759           0 :                 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
     760           0 : }
     761             : 
     762           0 : void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx)
     763             : {
     764           0 :         int mode, ret = 0;
     765           0 :         struct zebra_pbr_ipset_entry ipset_entry;
     766           0 :         struct zebra_pbr_ipset ipset;
     767             : 
     768           0 :         if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD)
     769             :                 mode = 1;
     770             :         else
     771           0 :                 mode = 0;
     772             : 
     773           0 :         dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry);
     774           0 :         dplane_ctx_get_pbr_ipset(ctx, &ipset);
     775             : 
     776           0 :         ipset_entry.backpointer = &ipset;
     777             : 
     778           0 :         ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry);
     779           0 :         if (ret)
     780           0 :                 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
     781             :         else
     782           0 :                 dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
     783           0 : }
     784             : 
     785           0 : static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data)
     786             : {
     787           0 :         struct zebra_pbr_rule *rule = b->data;
     788           0 :         int *sock = data;
     789             : 
     790           0 :         if (rule->sock == *sock) {
     791           0 :                 (void)dplane_pbr_rule_delete(rule);
     792           0 :                 pbr_rule_free(rule, true);
     793             :         }
     794           0 : }
     795             : 
     796           0 : static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data)
     797             : {
     798           0 :         struct zebra_pbr_ipset *ipset = b->data;
     799           0 :         int *sock = data;
     800             : 
     801           0 :         if (ipset->sock == *sock) {
     802           0 :                 if (hash_release(zrouter.ipset_hash, ipset))
     803           0 :                         zebra_pbr_ipset_free(ipset);
     804             :                 else
     805           0 :                         hook_call(zebra_pbr_ipset_update, 0, ipset);
     806             :         }
     807           0 : }
     808             : 
     809           0 : static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data)
     810             : {
     811           0 :         struct zebra_pbr_ipset_entry *ipset = b->data;
     812           0 :         int *sock = data;
     813             : 
     814           0 :         if (ipset->sock == *sock) {
     815           0 :                 if (hash_release(zrouter.ipset_entry_hash, ipset))
     816           0 :                         zebra_pbr_ipset_entry_free(ipset);
     817             :                 else
     818           0 :                         hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
     819             :         }
     820           0 : }
     821             : 
     822           0 : static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data)
     823             : {
     824           0 :         struct zebra_pbr_iptable *iptable = b->data;
     825           0 :         int *sock = data;
     826             : 
     827           0 :         if (iptable->sock == *sock) {
     828           0 :                 if (hash_release(zrouter.iptable_hash, iptable))
     829           0 :                         _zebra_pbr_iptable_free_all(iptable, true);
     830             :                 else
     831           0 :                         hook_call(zebra_pbr_iptable_update, 0, iptable);
     832             :         }
     833           0 : }
     834             : 
     835           6 : static int zebra_pbr_client_close_cleanup(struct zserv *client)
     836             : {
     837           6 :         int sock = client->sock;
     838             : 
     839           6 :         if (!sock)
     840             :                 return 0;
     841           6 :         hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock);
     842           6 :         hash_iterate(zrouter.iptable_hash, zebra_pbr_cleanup_iptable, &sock);
     843           6 :         hash_iterate(zrouter.ipset_entry_hash, zebra_pbr_cleanup_ipset_entry,
     844             :                      &sock);
     845           6 :         hash_iterate(zrouter.ipset_hash, zebra_pbr_cleanup_ipset, &sock);
     846           6 :         return 1;
     847             : }
     848             : 
     849           3 : void zebra_pbr_init(void)
     850             : {
     851           3 :         hook_register(zserv_client_close, zebra_pbr_client_close_cleanup);
     852           3 : }
     853             : 
     854           0 : static void *pbr_ipset_alloc_intern(void *arg)
     855             : {
     856           0 :         struct zebra_pbr_ipset *zpi;
     857           0 :         struct zebra_pbr_ipset *new;
     858             : 
     859           0 :         zpi = (struct zebra_pbr_ipset *)arg;
     860             : 
     861           0 :         new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset));
     862             : 
     863           0 :         memcpy(new, zpi, sizeof(*zpi));
     864             : 
     865           0 :         return new;
     866             : }
     867             : 
     868           0 : void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset)
     869             : {
     870           0 :         (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern);
     871           0 :         (void)dplane_pbr_ipset_add(ipset);
     872           0 : }
     873             : 
     874           0 : void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset)
     875             : {
     876           0 :         struct zebra_pbr_ipset *lookup;
     877             : 
     878           0 :         lookup = hash_lookup(zrouter.ipset_hash, ipset);
     879           0 :         (void)dplane_pbr_ipset_delete(ipset);
     880           0 :         if (lookup) {
     881           0 :                 hash_release(zrouter.ipset_hash, lookup);
     882           0 :                 XFREE(MTYPE_PBR_OBJ, lookup);
     883             :         } else
     884           0 :                 zlog_debug(
     885             :                         "%s: IPSet Entry being deleted we know nothing about",
     886             :                         __func__);
     887           0 : }
     888             : 
     889             : struct pbr_ipset_name_lookup {
     890             :         struct zebra_pbr_ipset *ipset;
     891             :         char ipset_name[ZEBRA_IPSET_NAME_SIZE];
     892             : };
     893             : 
     894           0 : const char *zebra_pbr_ipset_type2str(uint32_t type)
     895             : {
     896           0 :         return lookup_msg(ipset_type_msg, type,
     897             :                           "Unrecognized IPset Type");
     898             : }
     899             : 
     900           0 : static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg)
     901             : {
     902           0 :         struct pbr_ipset_name_lookup *pinl =
     903             :                 (struct pbr_ipset_name_lookup *)arg;
     904           0 :         struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
     905             : 
     906           0 :         if (!strncmp(pinl->ipset_name, zpi->ipset_name,
     907             :                      ZEBRA_IPSET_NAME_SIZE)) {
     908           0 :                 pinl->ipset = zpi;
     909           0 :                 return HASHWALK_ABORT;
     910             :         }
     911             :         return HASHWALK_CONTINUE;
     912             : }
     913             : 
     914           0 : struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname)
     915             : {
     916           0 :         struct pbr_ipset_name_lookup pinl;
     917           0 :         struct pbr_ipset_name_lookup *ptr = &pinl;
     918             : 
     919           0 :         if (!ipsetname)
     920             :                 return NULL;
     921           0 :         memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup));
     922           0 :         snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s",
     923             :                 ipsetname);
     924           0 :         hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr);
     925           0 :         return ptr->ipset;
     926             : }
     927             : 
     928           0 : static void *pbr_ipset_entry_alloc_intern(void *arg)
     929             : {
     930           0 :         struct zebra_pbr_ipset_entry *zpi;
     931           0 :         struct zebra_pbr_ipset_entry *new;
     932             : 
     933           0 :         zpi = (struct zebra_pbr_ipset_entry *)arg;
     934             : 
     935           0 :         new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry));
     936             : 
     937           0 :         memcpy(new, zpi, sizeof(*zpi));
     938             : 
     939           0 :         return new;
     940             : }
     941             : 
     942           0 : void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
     943             : {
     944           0 :         (void)hash_get(zrouter.ipset_entry_hash, ipset,
     945             :                        pbr_ipset_entry_alloc_intern);
     946           0 :         (void)dplane_pbr_ipset_entry_add(ipset);
     947           0 : }
     948             : 
     949           0 : void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset)
     950             : {
     951           0 :         struct zebra_pbr_ipset_entry *lookup;
     952             : 
     953           0 :         lookup = hash_lookup(zrouter.ipset_entry_hash, ipset);
     954           0 :         (void)dplane_pbr_ipset_entry_delete(ipset);
     955           0 :         if (lookup) {
     956           0 :                 hash_release(zrouter.ipset_entry_hash, lookup);
     957           0 :                 XFREE(MTYPE_PBR_OBJ, lookup);
     958             :         } else
     959           0 :                 zlog_debug("%s: IPSet being deleted we know nothing about",
     960             :                            __func__);
     961           0 : }
     962             : 
     963           0 : static void *pbr_iptable_alloc_intern(void *arg)
     964             : {
     965           0 :         struct zebra_pbr_iptable *zpi;
     966           0 :         struct zebra_pbr_iptable *new;
     967           0 :         struct listnode *ln;
     968           0 :         char *ifname;
     969             : 
     970           0 :         zpi = (struct zebra_pbr_iptable *)arg;
     971             : 
     972           0 :         new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable));
     973             : 
     974             :         /* Deep structure copy */
     975           0 :         memcpy(new, zpi, sizeof(*zpi));
     976           0 :         new->interface_name_list = list_new();
     977             : 
     978           0 :         if (zpi->interface_name_list) {
     979           0 :                 for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname))
     980           0 :                         listnode_add(new->interface_name_list,
     981             :                                      XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname));
     982             :         }
     983             : 
     984           0 :         return new;
     985             : }
     986             : 
     987           0 : void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable)
     988             : {
     989           0 :         struct zebra_pbr_iptable *ipt_hash;
     990             : 
     991           0 :         ipt_hash = hash_get(zrouter.iptable_hash, iptable,
     992             :                             pbr_iptable_alloc_intern);
     993           0 :         (void)dplane_pbr_iptable_add(ipt_hash);
     994           0 : }
     995             : 
     996           0 : void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
     997             : {
     998           0 :         struct zebra_pbr_iptable *lookup;
     999             : 
    1000           0 :         lookup = hash_lookup(zrouter.iptable_hash, iptable);
    1001           0 :         (void)dplane_pbr_iptable_delete(iptable);
    1002           0 :         if (lookup) {
    1003           0 :                 struct listnode *node, *nnode;
    1004           0 :                 char *name;
    1005             : 
    1006           0 :                 hash_release(zrouter.iptable_hash, lookup);
    1007           0 :                 for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
    1008             :                                        node, nnode, name)) {
    1009           0 :                         XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
    1010           0 :                         list_delete_node(iptable->interface_name_list,
    1011             :                                          node);
    1012             :                 }
    1013           0 :                 list_delete(&iptable->interface_name_list);
    1014           0 :                 XFREE(MTYPE_PBR_OBJ, lookup);
    1015             :         } else
    1016           0 :                 zlog_debug("%s: IPTable being deleted we know nothing about",
    1017             :                            __func__);
    1018           0 : }
    1019             : 
    1020             : /*
    1021             :  * Handle success or failure of rule (un)install in the kernel.
    1022             :  */
    1023           0 : void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx)
    1024             : {
    1025           0 :         enum zebra_dplane_result res;
    1026           0 :         enum dplane_op_e op;
    1027             : 
    1028           0 :         res = dplane_ctx_get_status(ctx);
    1029           0 :         op = dplane_ctx_get_op(ctx);
    1030           0 :         if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE)
    1031           0 :                 zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1032             :                                                      ? ZAPI_RULE_INSTALLED
    1033             :                                                      : ZAPI_RULE_FAIL_INSTALL);
    1034           0 :         else if (op == DPLANE_OP_RULE_DELETE)
    1035           0 :                 zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1036             :                                                      ? ZAPI_RULE_REMOVED
    1037             :                                                      : ZAPI_RULE_FAIL_REMOVE);
    1038             :         else if (op == DPLANE_OP_IPTABLE_ADD)
    1039           0 :                 zsend_iptable_notify_owner(ctx,
    1040             :                                            res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1041             :                                                 ? ZAPI_IPTABLE_INSTALLED
    1042             :                                                 : ZAPI_IPTABLE_FAIL_INSTALL);
    1043             :         else if (op == DPLANE_OP_IPTABLE_DELETE)
    1044           0 :                 zsend_iptable_notify_owner(ctx,
    1045             :                                            res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1046             :                                                 ? ZAPI_IPTABLE_REMOVED
    1047             :                                                 : ZAPI_IPTABLE_FAIL_REMOVE);
    1048             :         else if (op == DPLANE_OP_IPSET_ADD)
    1049           0 :                 zsend_ipset_notify_owner(ctx,
    1050             :                                          res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1051             :                                                  ? ZAPI_IPSET_INSTALLED
    1052             :                                                  : ZAPI_IPSET_FAIL_INSTALL);
    1053             :         else if (op == DPLANE_OP_IPSET_DELETE)
    1054           0 :                 zsend_ipset_notify_owner(ctx,
    1055             :                                          res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1056             :                                                  ? ZAPI_IPSET_REMOVED
    1057             :                                                  : ZAPI_IPSET_FAIL_REMOVE);
    1058             :         else if (op == DPLANE_OP_IPSET_ENTRY_ADD)
    1059           0 :                 zsend_ipset_entry_notify_owner(
    1060             :                         ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1061             :                                      ? ZAPI_IPSET_ENTRY_INSTALLED
    1062             :                                      : ZAPI_IPSET_ENTRY_FAIL_INSTALL);
    1063             :         else if (op == DPLANE_OP_IPSET_ENTRY_DELETE)
    1064           0 :                 zsend_ipset_entry_notify_owner(
    1065             :                         ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS
    1066             :                                      ? ZAPI_IPSET_ENTRY_REMOVED
    1067             :                                      : ZAPI_IPSET_ENTRY_FAIL_REMOVE);
    1068             :         else
    1069           0 :                 flog_err(
    1070             :                         EC_ZEBRA_PBR_RULE_UPDATE,
    1071             :                         "Context received in pbr rule dplane result handler with incorrect OP code (%u)",
    1072             :                         op);
    1073           0 : }
    1074             : 
    1075             : /*
    1076             :  * Handle rule delete notification from kernel.
    1077             :  */
    1078           0 : int kernel_pbr_rule_del(struct zebra_pbr_rule *rule)
    1079             : {
    1080           0 :         return 0;
    1081             : }
    1082             : 
    1083             : struct zebra_pbr_ipset_entry_unique_display {
    1084             :         struct zebra_pbr_ipset *zpi;
    1085             :         struct vty *vty;
    1086             :         struct zebra_ns *zns;
    1087             : };
    1088             : 
    1089             : 
    1090           0 : static const char *zebra_pbr_prefix2str(union prefixconstptr pu,
    1091             :                                         char *str, int size)
    1092             : {
    1093           0 :         const struct prefix *p = pu.p;
    1094           0 :         char buf[PREFIX2STR_BUFFER];
    1095             : 
    1096           0 :         if ((p->family == AF_INET && p->prefixlen == IPV4_MAX_BITLEN)
    1097           0 :             || (p->family == AF_INET6 && p->prefixlen == IPV6_MAX_BITLEN)) {
    1098           0 :                 snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix,
    1099             :                                                     buf, PREFIX2STR_BUFFER));
    1100           0 :                 return str;
    1101             :         }
    1102           0 :         return prefix2str(pu, str, size);
    1103             : }
    1104             : 
    1105           0 : static void zebra_pbr_display_icmp(struct vty *vty,
    1106             :                                    struct zebra_pbr_ipset_entry *zpie)
    1107             : {
    1108           0 :         char decoded_str[20];
    1109           0 :         uint16_t port;
    1110           0 :         struct zebra_pbr_ipset *zpi;
    1111             : 
    1112           0 :         zpi = zpie->backpointer;
    1113             : 
    1114             :         /* range icmp type */
    1115           0 :         if (zpie->src_port_max || zpie->dst_port_max) {
    1116           0 :                 vty_out(vty, ":icmp:[type <%u:%u>;code <%u:%u>",
    1117           0 :                         zpie->src_port_min, zpie->src_port_max,
    1118           0 :                         zpie->dst_port_min, zpie->dst_port_max);
    1119             :         } else {
    1120           0 :                 port = ((zpie->src_port_min << 8) & 0xff00) +
    1121           0 :                         (zpie->dst_port_min & 0xff);
    1122           0 :                 memset(decoded_str, 0, sizeof(decoded_str));
    1123           0 :                 snprintf(decoded_str, sizeof(decoded_str), "%u/%u",
    1124             :                          zpie->src_port_min, zpie->dst_port_min);
    1125           0 :                 vty_out(vty, ":%s:%s",
    1126           0 :                         zpi->family == AF_INET6 ? "ipv6-icmp" : "icmp",
    1127           0 :                         lookup_msg(zpi->family == AF_INET6 ?
    1128             :                                    icmpv6_typecode_str : icmp_typecode_str,
    1129             :                                    port, decoded_str));
    1130             :         }
    1131           0 : }
    1132             : 
    1133           0 : static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm,
    1134             :                             uint16_t port_min, uint16_t port_max,
    1135             :                             uint8_t proto)
    1136             : {
    1137           0 :         if (!(filter_bm & PBR_FILTER_PROTO)) {
    1138           0 :                 if (port_max)
    1139           0 :                         vty_out(vty, ":udp/tcp:%d-%d",
    1140             :                                 port_min, port_max);
    1141             :                 else
    1142           0 :                         vty_out(vty, ":udp/tcp:%d",
    1143             :                                 port_min);
    1144             :         } else {
    1145           0 :                 if (port_max)
    1146           0 :                         vty_out(vty, ":proto %d:%d-%d",
    1147             :                                 proto, port_min, port_max);
    1148             :                 else
    1149           0 :                         vty_out(vty, ":proto %d:%d",
    1150             :                                 proto, port_min);
    1151             :         }
    1152           0 : }
    1153             : 
    1154           0 : static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket,
    1155             :                                              void *arg)
    1156             : {
    1157           0 :         struct zebra_pbr_ipset_entry_unique_display *unique =
    1158             :                 (struct zebra_pbr_ipset_entry_unique_display *)arg;
    1159           0 :         struct zebra_pbr_ipset *zpi = unique->zpi;
    1160           0 :         struct vty *vty = unique->vty;
    1161           0 :         struct zebra_pbr_ipset_entry *zpie =
    1162             :                 (struct zebra_pbr_ipset_entry *)bucket->data;
    1163           0 :         uint64_t pkts = 0, bytes = 0;
    1164           0 :         int ret = 0;
    1165             : 
    1166           0 :         if (zpie->backpointer != zpi)
    1167             :                 return HASHWALK_CONTINUE;
    1168             : 
    1169           0 :         if ((zpi->type == IPSET_NET_NET) ||
    1170             :             (zpi->type == IPSET_NET_PORT_NET)) {
    1171           0 :                 char buf[PREFIX_STRLEN];
    1172             : 
    1173           0 :                 zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
    1174           0 :                 vty_out(vty, "\tfrom %s", buf);
    1175           0 :                 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
    1176           0 :                     zpie->proto != IPPROTO_ICMP)
    1177           0 :                         zebra_pbr_display_port(vty, zpie->filter_bm,
    1178           0 :                                                zpie->src_port_min,
    1179           0 :                                                zpie->src_port_max,
    1180             :                                                zpie->proto);
    1181           0 :                 vty_out(vty, " to ");
    1182           0 :                 zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
    1183           0 :                 vty_out(vty, "%s", buf);
    1184           0 :                 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
    1185           0 :                     zpie->proto != IPPROTO_ICMP)
    1186           0 :                         zebra_pbr_display_port(vty, zpie->filter_bm,
    1187           0 :                                                zpie->dst_port_min,
    1188           0 :                                                zpie->dst_port_max,
    1189             :                                                zpie->proto);
    1190           0 :                 if (zpie->proto == IPPROTO_ICMP)
    1191           0 :                         zebra_pbr_display_icmp(vty, zpie);
    1192           0 :         } else if ((zpi->type == IPSET_NET) ||
    1193             :                    (zpi->type == IPSET_NET_PORT)) {
    1194           0 :                 char buf[PREFIX_STRLEN];
    1195             : 
    1196           0 :                 if (zpie->filter_bm & PBR_FILTER_SRC_IP) {
    1197           0 :                         zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf));
    1198           0 :                         vty_out(vty, "\tfrom %s", buf);
    1199             :                 }
    1200           0 :                 if (zpie->filter_bm & PBR_FILTER_SRC_PORT &&
    1201           0 :                     zpie->proto != IPPROTO_ICMP)
    1202           0 :                         zebra_pbr_display_port(vty, zpie->filter_bm,
    1203           0 :                                                zpie->src_port_min,
    1204           0 :                                                zpie->src_port_max,
    1205             :                                                zpie->proto);
    1206           0 :                 if (zpie->filter_bm & PBR_FILTER_DST_IP) {
    1207           0 :                         zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf));
    1208           0 :                         vty_out(vty, "\tto %s", buf);
    1209             :                 }
    1210           0 :                 if (zpie->filter_bm & PBR_FILTER_DST_PORT &&
    1211           0 :                     zpie->proto != IPPROTO_ICMP)
    1212           0 :                         zebra_pbr_display_port(vty, zpie->filter_bm,
    1213           0 :                                                zpie->dst_port_min,
    1214           0 :                                                zpie->dst_port_max,
    1215             :                                                zpie->proto);
    1216           0 :                 if (zpie->proto == IPPROTO_ICMP)
    1217           0 :                         zebra_pbr_display_icmp(vty, zpie);
    1218             :         }
    1219           0 :         vty_out(vty, " (%u)\n", zpie->unique);
    1220             : 
    1221           0 :         ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts,
    1222             :                         &bytes);
    1223           0 :         if (ret && pkts > 0)
    1224           0 :                 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
    1225             :                         pkts, bytes);
    1226             :         return HASHWALK_CONTINUE;
    1227             : }
    1228             : 
    1229           0 : static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg)
    1230             : {
    1231           0 :         struct zebra_pbr_env_display *uniqueipset =
    1232             :                 (struct zebra_pbr_env_display *)arg;
    1233           0 :         struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data;
    1234           0 :         struct zebra_pbr_ipset_entry_unique_display unique;
    1235           0 :         struct vty *vty = uniqueipset->vty;
    1236           0 :         struct zebra_ns *zns = uniqueipset->zns;
    1237             : 
    1238           0 :         vty_out(vty, "IPset %s type %s family %s\n", zpi->ipset_name,
    1239             :                 zebra_pbr_ipset_type2str(zpi->type),
    1240           0 :                 family2str(zpi->family));
    1241           0 :         unique.vty = vty;
    1242           0 :         unique.zpi = zpi;
    1243           0 :         unique.zns = zns;
    1244           0 :         hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb,
    1245             :                   &unique);
    1246           0 :         vty_out(vty, "\n");
    1247           0 :         return HASHWALK_CONTINUE;
    1248             : }
    1249             : 
    1250           0 : size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
    1251             :                                    uint16_t tcp_val)
    1252             : {
    1253           0 :         size_t len_written = 0;
    1254           0 :         static struct message nt = {0};
    1255           0 :         const struct message *pnt;
    1256           0 :         int incr = 0;
    1257             : 
    1258           0 :         for (pnt = tcp_value_str;
    1259           0 :              memcmp(pnt, &nt, sizeof(struct message)); pnt++)
    1260           0 :                 if (pnt->key & tcp_val) {
    1261           0 :                         len_written += snprintf(buffer + len_written,
    1262             :                                                 len - len_written,
    1263             :                                                 "%s%s", incr ?
    1264           0 :                                                 ",":"", pnt->str);
    1265           0 :                         incr++;
    1266             :                 }
    1267           0 :         return len_written;
    1268             : }
    1269             : 
    1270             : /*
    1271             :  */
    1272           0 : void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname)
    1273             : {
    1274           0 :         struct zebra_pbr_ipset *zpi;
    1275           0 :         struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
    1276           0 :         struct zebra_pbr_ipset_entry_unique_display unique;
    1277           0 :         struct zebra_pbr_env_display uniqueipset;
    1278             : 
    1279           0 :         if (ipsetname) {
    1280           0 :                 zpi = zebra_pbr_lookup_ipset_pername(ipsetname);
    1281           0 :                 if (!zpi) {
    1282           0 :                         vty_out(vty, "No IPset %s found\n", ipsetname);
    1283           0 :                         return;
    1284             :                 }
    1285           0 :                 vty_out(vty, "IPset %s type %s family %s\n", ipsetname,
    1286             :                         zebra_pbr_ipset_type2str(zpi->type),
    1287           0 :                         family2str(zpi->family));
    1288           0 :                 unique.vty = vty;
    1289           0 :                 unique.zpi = zpi;
    1290           0 :                 unique.zns = zns;
    1291           0 :                 hash_walk(zrouter.ipset_entry_hash,
    1292             :                           zebra_pbr_show_ipset_entry_walkcb, &unique);
    1293           0 :                 return;
    1294             :         }
    1295           0 :         uniqueipset.zns = zns;
    1296           0 :         uniqueipset.vty = vty;
    1297           0 :         uniqueipset.name = NULL;
    1298           0 :         hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb,
    1299             :                   &uniqueipset);
    1300             : }
    1301             : 
    1302             : struct pbr_rule_fwmark_lookup {
    1303             :         struct zebra_pbr_rule *ptr;
    1304             :         uint32_t fwmark;
    1305             : };
    1306             : 
    1307           0 : static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket,
    1308             :                                                void *arg)
    1309             : {
    1310           0 :         struct pbr_rule_fwmark_lookup *iprule =
    1311             :                 (struct pbr_rule_fwmark_lookup *)arg;
    1312           0 :         struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data;
    1313             : 
    1314           0 :         if (iprule->fwmark == zpr->rule.filter.fwmark) {
    1315           0 :                 iprule->ptr = zpr;
    1316           0 :                 return HASHWALK_ABORT;
    1317             :         }
    1318             :         return HASHWALK_CONTINUE;
    1319             : }
    1320             : 
    1321           0 : static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable,
    1322             :                                        struct vty *vty,
    1323             :                                        struct zebra_ns *zns)
    1324             : {
    1325           0 :         int ret;
    1326           0 :         uint64_t pkts = 0, bytes = 0;
    1327             : 
    1328           0 :         vty_out(vty, "IPtable %s family %s action %s (%u)\n",
    1329           0 :                 iptable->ipset_name,
    1330           0 :                 family2str(iptable->family),
    1331           0 :                 iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect",
    1332             :                 iptable->unique);
    1333           0 :         if (iptable->type == IPSET_NET_PORT ||
    1334             :             iptable->type == IPSET_NET_PORT_NET) {
    1335           0 :                 if (!(iptable->filter_bm & MATCH_ICMP_SET)) {
    1336           0 :                         if (iptable->filter_bm & PBR_FILTER_DST_PORT)
    1337           0 :                                 vty_out(vty, "\t lookup dst port\n");
    1338           0 :                         else if (iptable->filter_bm & PBR_FILTER_SRC_PORT)
    1339           0 :                                 vty_out(vty, "\t lookup src port\n");
    1340             :                 }
    1341             :         }
    1342           0 :         if (iptable->pkt_len_min || iptable->pkt_len_max) {
    1343           0 :                 if (!iptable->pkt_len_max)
    1344           0 :                         vty_out(vty, "\t pkt len %u\n",
    1345           0 :                                 iptable->pkt_len_min);
    1346             :                 else
    1347           0 :                         vty_out(vty, "\t pkt len [%u;%u]\n",
    1348           0 :                                 iptable->pkt_len_min,
    1349             :                                 iptable->pkt_len_max);
    1350             :         }
    1351           0 :         if (iptable->tcp_flags || iptable->tcp_mask_flags) {
    1352           0 :                 char tcp_flag_str[64];
    1353           0 :                 char tcp_flag_mask_str[64];
    1354             : 
    1355           0 :                 zebra_pbr_tcpflags_snprintf(tcp_flag_str,
    1356             :                                             sizeof(tcp_flag_str),
    1357           0 :                                             iptable->tcp_flags);
    1358           0 :                 zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str,
    1359             :                                             sizeof(tcp_flag_mask_str),
    1360           0 :                                             iptable->tcp_mask_flags);
    1361           0 :                 vty_out(vty, "\t tcpflags [%s/%s]\n",
    1362             :                         tcp_flag_str, tcp_flag_mask_str);
    1363             :         }
    1364           0 :         if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) {
    1365           0 :                 vty_out(vty, "\t dscp %s %d\n",
    1366           0 :                         iptable->filter_bm & MATCH_DSCP_INVERSE_SET ?
    1367           0 :                         "not" : "", iptable->dscp_value);
    1368             :         }
    1369           0 :         if (iptable->filter_bm & (MATCH_FLOW_LABEL_SET |
    1370             :                                   MATCH_FLOW_LABEL_INVERSE_SET)) {
    1371           0 :                 vty_out(vty, "\t flowlabel %s %d\n",
    1372           0 :                         iptable->filter_bm & MATCH_FLOW_LABEL_INVERSE_SET ?
    1373           0 :                         "not" : "", iptable->flow_label);
    1374             :         }
    1375           0 :         if (iptable->fragment) {
    1376           0 :                 char val_str[10];
    1377             : 
    1378           0 :                 snprintf(val_str, sizeof(val_str), "%d", iptable->fragment);
    1379           0 :                 vty_out(vty, "\t fragment%s %s\n",
    1380           0 :                         iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ?
    1381             :                         " not" : "", lookup_msg(fragment_value_str,
    1382           0 :                                                iptable->fragment, val_str));
    1383             :         }
    1384           0 :         if (iptable->protocol) {
    1385           0 :                 vty_out(vty, "\t protocol %d\n",
    1386             :                         iptable->protocol);
    1387             :         }
    1388           0 :         ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts,
    1389             :                         &bytes);
    1390           0 :         if (ret && pkts > 0)
    1391           0 :                 vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n",
    1392             :                         pkts, bytes);
    1393           0 :         if (iptable->action != ZEBRA_IPTABLES_DROP) {
    1394           0 :                 struct pbr_rule_fwmark_lookup prfl;
    1395             : 
    1396           0 :                 prfl.fwmark = iptable->fwmark;
    1397           0 :                 prfl.ptr = NULL;
    1398           0 :                 hash_walk(zrouter.rules_hash,
    1399             :                           &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl);
    1400           0 :                 if (prfl.ptr) {
    1401           0 :                         struct zebra_pbr_rule *zpr = prfl.ptr;
    1402             : 
    1403           0 :                         vty_out(vty, "\t table %u, fwmark %u\n",
    1404             :                                 zpr->rule.action.table,
    1405             :                                 prfl.fwmark);
    1406             :                 }
    1407             :         }
    1408           0 : }
    1409             : 
    1410           0 : static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg)
    1411             : {
    1412           0 :         struct zebra_pbr_iptable *iptable =
    1413             :                 (struct zebra_pbr_iptable *)bucket->data;
    1414           0 :         struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg;
    1415           0 :         struct vty *vty = env->vty;
    1416           0 :         struct zebra_ns *zns = env->zns;
    1417           0 :         char *iptable_name = env->name;
    1418             : 
    1419           0 :         if (!iptable_name)
    1420           0 :                 zebra_pbr_show_iptable_unit(iptable, vty, zns);
    1421           0 :         else if (!strncmp(iptable_name,
    1422           0 :                           iptable->ipset_name,
    1423             :                           ZEBRA_IPSET_NAME_SIZE))
    1424           0 :                 zebra_pbr_show_iptable_unit(iptable, vty, zns);
    1425           0 :         return HASHWALK_CONTINUE;
    1426             : }
    1427             : 
    1428           0 : void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name)
    1429             : {
    1430           0 :         struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
    1431           0 :         struct zebra_pbr_env_display env;
    1432             : 
    1433           0 :         env.vty = vty;
    1434           0 :         env.zns = zns;
    1435           0 :         env.name = iptable_name;
    1436           0 :         hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env);
    1437           0 : }
    1438             : 
    1439           0 : void zebra_pbr_iptable_update_interfacelist(struct stream *s,
    1440             :                                             struct zebra_pbr_iptable *zpi)
    1441             : {
    1442           0 :         uint32_t i = 0, index;
    1443           0 :         struct interface *ifp;
    1444           0 :         char *name;
    1445             : 
    1446           0 :         for (i = 0; i < zpi->nb_interface; i++) {
    1447           0 :                 STREAM_GETL(s, index);
    1448           0 :                 ifp = if_lookup_by_index(index, zpi->vrf_id);
    1449           0 :                 if (!ifp)
    1450           0 :                         continue;
    1451           0 :                 name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name);
    1452           0 :                 listnode_add(zpi->interface_name_list, name);
    1453             :         }
    1454           0 : stream_failure:
    1455           0 :         return;
    1456             : }

Generated by: LCOV version v1.16-topotato