back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_neigh.c (source / functions) Hit Total Coverage
Test: test_bgp_rmap_extcommunity_none.py::TestBGPExtCommunity Lines: 41 125 32.8 %
Date: 2023-02-24 18:37:31 Functions: 10 19 52.6 %

          Line data    Source code
       1             : /*
       2             :  * Zebra neighbor table management
       3             :  *
       4             :  * Copyright (C) 2021 Nvidia
       5             :  * Anuradha Karuppiah
       6             :  *
       7             :  * This file is part of FRR.
       8             :  *
       9             :  * FRR is free software; you can redistribute it and/or modify it
      10             :  * under the terms of the GNU General Public License as published by the
      11             :  * Free Software Foundation; either version 2, or (at your option) any
      12             :  * later version.
      13             :  *
      14             :  * FRR is distributed in the hope that it will be useful, but
      15             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * General Public License for more details.
      18             :  */
      19             : 
      20             : #include <zebra.h>
      21             : 
      22             : #include "command.h"
      23             : #include "hash.h"
      24             : #include "if.h"
      25             : #include "jhash.h"
      26             : #include "linklist.h"
      27             : #include "log.h"
      28             : #include "memory.h"
      29             : #include "prefix.h"
      30             : #include "stream.h"
      31             : #include "table.h"
      32             : 
      33             : #include "zebra/zebra_router.h"
      34             : #include "zebra/debug.h"
      35             : #include "zebra/interface.h"
      36             : #include "zebra/rib.h"
      37             : #include "zebra/rt.h"
      38             : #include "zebra/rt_netlink.h"
      39             : #include "zebra/zebra_errors.h"
      40             : #include "zebra/interface.h"
      41             : #include "zebra/zebra_neigh.h"
      42             : #include "zebra/zebra_pbr.h"
      43             : 
      44           6 : DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_INFO, "Zebra neigh table");
      45           6 : DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_ENT, "Zebra neigh entry");
      46             : 
      47           0 : static int zebra_neigh_rb_cmp(const struct zebra_neigh_ent *n1,
      48             :                               const struct zebra_neigh_ent *n2)
      49             : {
      50           0 :         if (n1->ifindex < n2->ifindex)
      51             :                 return -1;
      52             : 
      53           0 :         if (n1->ifindex > n2->ifindex)
      54             :                 return 1;
      55             : 
      56           0 :         if (n1->ip.ipa_type < n2->ip.ipa_type)
      57             :                 return -1;
      58             : 
      59           0 :         if (n1->ip.ipa_type > n2->ip.ipa_type)
      60             :                 return 1;
      61             : 
      62           0 :         if (n1->ip.ipa_type == AF_INET) {
      63           0 :                 if (n1->ip.ipaddr_v4.s_addr < n2->ip.ipaddr_v4.s_addr)
      64             :                         return -1;
      65             : 
      66           0 :                 if (n1->ip.ipaddr_v4.s_addr > n2->ip.ipaddr_v4.s_addr)
      67             :                         return 1;
      68             : 
      69           0 :                 return 0;
      70             :         }
      71             : 
      72           0 :         return memcmp(&n1->ip.ipaddr_v6, &n2->ip.ipaddr_v6, IPV6_MAX_BYTELEN);
      73             : }
      74           0 : RB_GENERATE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_neigh_rb_cmp);
      75             : 
      76           2 : static struct zebra_neigh_ent *zebra_neigh_find(ifindex_t ifindex,
      77             :                                                 struct ipaddr *ip)
      78             : {
      79           2 :         struct zebra_neigh_ent tmp;
      80             : 
      81           2 :         tmp.ifindex = ifindex;
      82           2 :         memcpy(&tmp.ip, ip, sizeof(*ip));
      83           2 :         return RB_FIND(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, &tmp);
      84             : }
      85             : 
      86             : static struct zebra_neigh_ent *
      87           2 : zebra_neigh_new(ifindex_t ifindex, struct ipaddr *ip, struct ethaddr *mac)
      88             : {
      89           2 :         struct zebra_neigh_ent *n;
      90             : 
      91           2 :         n = XCALLOC(MTYPE_ZNEIGH_ENT, sizeof(struct zebra_neigh_ent));
      92             : 
      93           2 :         memcpy(&n->ip, ip, sizeof(*ip));
      94           2 :         n->ifindex = ifindex;
      95           2 :         if (mac) {
      96           2 :                 memcpy(&n->mac, mac, sizeof(*mac));
      97           2 :                 n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
      98             :         }
      99             : 
     100             :         /* Add to rb_tree */
     101           2 :         if (RB_INSERT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n)) {
     102           0 :                 XFREE(MTYPE_ZNEIGH_ENT, n);
     103           0 :                 return NULL;
     104             :         }
     105             : 
     106             :         /* Initialise the pbr rule list */
     107           2 :         n->pbr_rule_list = list_new();
     108           2 :         listset_app_node_mem(n->pbr_rule_list);
     109             : 
     110           2 :         if (IS_ZEBRA_DEBUG_NEIGH)
     111           0 :                 zlog_debug("zebra neigh new if %d %pIA %pEA", n->ifindex,
     112             :                            &n->ip, &n->mac);
     113             : 
     114             :         return n;
     115             : }
     116             : 
     117           0 : static void zebra_neigh_pbr_rules_update(struct zebra_neigh_ent *n)
     118             : {
     119           0 :         struct zebra_pbr_rule *rule;
     120           0 :         struct listnode *node;
     121             : 
     122           0 :         for (ALL_LIST_ELEMENTS_RO(n->pbr_rule_list, node, rule))
     123           0 :                 dplane_pbr_rule_update(rule, rule);
     124           0 : }
     125             : 
     126           2 : static void zebra_neigh_free(struct zebra_neigh_ent *n)
     127             : {
     128           2 :         if (listcount(n->pbr_rule_list)) {
     129             :                 /* if rules are still using the neigh mark it as inactive and
     130             :                  * update the dataplane
     131             :                  */
     132           0 :                 if (n->flags & ZEBRA_NEIGH_ENT_ACTIVE) {
     133           0 :                         n->flags &= ~ZEBRA_NEIGH_ENT_ACTIVE;
     134           0 :                         memset(&n->mac, 0, sizeof(n->mac));
     135             :                 }
     136           0 :                 zebra_neigh_pbr_rules_update(n);
     137           0 :                 return;
     138             :         }
     139           2 :         if (IS_ZEBRA_DEBUG_NEIGH)
     140           0 :                 zlog_debug("zebra neigh free if %d %pIA %pEA", n->ifindex,
     141             :                            &n->ip, &n->mac);
     142             : 
     143             :         /* cleanup resources maintained against the neigh */
     144           2 :         list_delete(&n->pbr_rule_list);
     145             : 
     146           2 :         RB_REMOVE(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n);
     147             : 
     148           2 :         XFREE(MTYPE_ZNEIGH_ENT, n);
     149             : }
     150             : 
     151             : /* kernel neigh del */
     152           0 : void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip)
     153             : {
     154           0 :         struct zebra_neigh_ent *n;
     155             : 
     156           0 :         if (IS_ZEBRA_DEBUG_NEIGH)
     157           0 :                 zlog_debug("zebra neigh del if %s/%d %pIA", ifp->name,
     158             :                            ifp->ifindex, ip);
     159             : 
     160           0 :         n = zebra_neigh_find(ifp->ifindex, ip);
     161           0 :         if (!n)
     162             :                 return;
     163           0 :         zebra_neigh_free(n);
     164             : }
     165             : 
     166             : /* kernel neigh add */
     167           2 : void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
     168             :                      struct ethaddr *mac)
     169             : {
     170           2 :         struct zebra_neigh_ent *n;
     171             : 
     172           2 :         if (IS_ZEBRA_DEBUG_NEIGH)
     173           0 :                 zlog_debug("zebra neigh add if %s/%d %pIA %pEA", ifp->name,
     174             :                            ifp->ifindex, ip, mac);
     175             : 
     176           2 :         n = zebra_neigh_find(ifp->ifindex, ip);
     177           2 :         if (n) {
     178           0 :                 if (!memcmp(&n->mac, mac, sizeof(*mac)))
     179             :                         return;
     180             : 
     181           0 :                 memcpy(&n->mac, mac, sizeof(*mac));
     182           0 :                 n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
     183             : 
     184             :                 /* update rules linked to the neigh */
     185           0 :                 zebra_neigh_pbr_rules_update(n);
     186             :         } else {
     187           2 :                 zebra_neigh_new(ifp->ifindex, ip, mac);
     188             :         }
     189             : }
     190             : 
     191           0 : void zebra_neigh_deref(struct zebra_pbr_rule *rule)
     192             : {
     193           0 :         struct zebra_neigh_ent *n = rule->action.neigh;
     194             : 
     195           0 :         if (IS_ZEBRA_DEBUG_NEIGH)
     196           0 :                 zlog_debug("zebra neigh deref if %d %pIA by pbr rule %u",
     197             :                            n->ifindex, &n->ip, rule->rule.seq);
     198             : 
     199           0 :         rule->action.neigh = NULL;
     200             :         /* remove rule from the list and free if it is inactive */
     201           0 :         list_delete_node(n->pbr_rule_list, &rule->action.neigh_listnode);
     202           0 :         if (!(n->flags & ZEBRA_NEIGH_ENT_ACTIVE))
     203           0 :                 zebra_neigh_free(n);
     204           0 : }
     205             : 
     206             : /* XXX - this needs to work with evpn's neigh read */
     207           0 : static void zebra_neigh_read_on_first_ref(void)
     208             : {
     209           0 :         static bool neigh_read_done;
     210             : 
     211           0 :         if (!neigh_read_done) {
     212           0 :                 neigh_read(zebra_ns_lookup(NS_DEFAULT));
     213           0 :                 neigh_read_done = true;
     214             :         }
     215           0 : }
     216             : 
     217           0 : void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
     218             :                      struct zebra_pbr_rule *rule)
     219             : {
     220           0 :         struct zebra_neigh_ent *n;
     221             : 
     222           0 :         if (IS_ZEBRA_DEBUG_NEIGH)
     223           0 :                 zlog_debug("zebra neigh ref if %d %pIA by pbr rule %u", ifindex,
     224             :                            ip, rule->rule.seq);
     225             : 
     226           0 :         zebra_neigh_read_on_first_ref();
     227           0 :         n = zebra_neigh_find(ifindex, ip);
     228           0 :         if (!n)
     229           0 :                 n = zebra_neigh_new(ifindex, ip, NULL);
     230             : 
     231             :         /* link the pbr entry to the neigh */
     232           0 :         if (rule->action.neigh == n)
     233             :                 return;
     234             : 
     235           0 :         if (rule->action.neigh)
     236           0 :                 zebra_neigh_deref(rule);
     237             : 
     238           0 :         rule->action.neigh = n;
     239           0 :         listnode_init(&rule->action.neigh_listnode, rule);
     240           0 :         listnode_add(n->pbr_rule_list, &rule->action.neigh_listnode);
     241             : }
     242             : 
     243           0 : static void zebra_neigh_show_one(struct vty *vty, struct zebra_neigh_ent *n)
     244             : {
     245           0 :         char mac_buf[ETHER_ADDR_STRLEN];
     246           0 :         char ip_buf[INET6_ADDRSTRLEN];
     247           0 :         struct interface *ifp;
     248             : 
     249           0 :         ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
     250           0 :                                         n->ifindex);
     251           0 :         ipaddr2str(&n->ip, ip_buf, sizeof(ip_buf));
     252           0 :         prefix_mac2str(&n->mac, mac_buf, sizeof(mac_buf));
     253           0 :         vty_out(vty, "%-20s %-30s %-18s %u\n", ifp ? ifp->name : "-", ip_buf,
     254           0 :                 mac_buf, listcount(n->pbr_rule_list));
     255           0 : }
     256             : 
     257           0 : void zebra_neigh_show(struct vty *vty)
     258             : {
     259           0 :         struct zebra_neigh_ent *n;
     260             : 
     261           0 :         vty_out(vty, "%-20s %-30s %-18s %s\n", "Interface", "Neighbor", "MAC",
     262             :                 "#Rules");
     263           0 :         RB_FOREACH (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree)
     264           0 :                 zebra_neigh_show_one(vty, n);
     265           0 : }
     266             : 
     267           2 : void zebra_neigh_init(void)
     268             : {
     269           2 :         zneigh_info = XCALLOC(MTYPE_ZNEIGH_INFO, sizeof(*zrouter.neigh_info));
     270           2 :         RB_INIT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree);
     271           2 : }
     272             : 
     273           2 : void zebra_neigh_terminate(void)
     274             : {
     275           2 :         struct zebra_neigh_ent *n, *next;
     276             : 
     277           2 :         if (!zrouter.neigh_info)
     278             :                 return;
     279             : 
     280           6 :         RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree,
     281             :                          next)
     282           2 :                 zebra_neigh_free(n);
     283           2 :         XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
     284             : }

Generated by: LCOV version v1.16-topotato