back to topotato report
topotato coverage report
Current view: top level - zebra - rt_netlink.c (source / functions) Hit Total Coverage
Test: test_bgp_disable_addpath_rx.py::BGPDisableAddpathRx Lines: 316 2122 14.9 %
Date: 2023-02-24 18:37:08 Functions: 22 79 27.8 %

          Line data    Source code
       1             : /* Kernel routing table updates using netlink over GNU/Linux system.
       2             :  * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra 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             :  * GNU Zebra 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 along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #ifdef HAVE_NETLINK
      24             : 
      25             : /* The following definition is to workaround an issue in the Linux kernel
      26             :  * header files with redefinition of 'struct in6_addr' in both
      27             :  * netinet/in.h and linux/in6.h.
      28             :  * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html
      29             :  */
      30             : #define _LINUX_IN6_H
      31             : 
      32             : #include <net/if_arp.h>
      33             : #include <linux/lwtunnel.h>
      34             : #include <linux/mpls_iptunnel.h>
      35             : #include <linux/seg6_iptunnel.h>
      36             : #include <linux/seg6_local.h>
      37             : #include <linux/neighbour.h>
      38             : #include <linux/rtnetlink.h>
      39             : #include <linux/nexthop.h>
      40             : 
      41             : /* Hack for GNU libc version 2. */
      42             : #ifndef MSG_TRUNC
      43             : #define MSG_TRUNC      0x20
      44             : #endif /* MSG_TRUNC */
      45             : 
      46             : #include "linklist.h"
      47             : #include "if.h"
      48             : #include "log.h"
      49             : #include "prefix.h"
      50             : #include "plist.h"
      51             : #include "plist_int.h"
      52             : #include "connected.h"
      53             : #include "table.h"
      54             : #include "memory.h"
      55             : #include "rib.h"
      56             : #include "thread.h"
      57             : #include "privs.h"
      58             : #include "nexthop.h"
      59             : #include "vrf.h"
      60             : #include "vty.h"
      61             : #include "mpls.h"
      62             : #include "vxlan.h"
      63             : #include "printfrr.h"
      64             : 
      65             : #include "zebra/zapi_msg.h"
      66             : #include "zebra/zebra_ns.h"
      67             : #include "zebra/zebra_vrf.h"
      68             : #include "zebra/rt.h"
      69             : #include "zebra/redistribute.h"
      70             : #include "zebra/interface.h"
      71             : #include "zebra/debug.h"
      72             : #include "zebra/rtadv.h"
      73             : #include "zebra/zebra_ptm.h"
      74             : #include "zebra/zebra_mpls.h"
      75             : #include "zebra/kernel_netlink.h"
      76             : #include "zebra/rt_netlink.h"
      77             : #include "zebra/zebra_nhg.h"
      78             : #include "zebra/zebra_mroute.h"
      79             : #include "zebra/zebra_vxlan.h"
      80             : #include "zebra/zebra_errors.h"
      81             : #include "zebra/zebra_evpn_mh.h"
      82             : #include "zebra/zebra_trace.h"
      83             : #include "zebra/zebra_neigh.h"
      84             : 
      85             : #ifndef AF_MPLS
      86             : #define AF_MPLS 28
      87             : #endif
      88             : 
      89             : /* Re-defining as I am unable to include <linux/if_bridge.h> which has the
      90             :  * UAPI for MAC sync. */
      91             : #ifndef _UAPI_LINUX_IF_BRIDGE_H
      92             : #define BR_SPH_LIST_SIZE 10
      93             : #endif
      94             : 
      95             : static vlanid_t filter_vlan = 0;
      96             : 
      97             : /* We capture whether the current kernel supports nexthop ids; by
      98             :  * default, we'll use them if possible. There's also a configuration
      99             :  * available to _disable_ use of kernel nexthops.
     100             :  */
     101             : static bool supports_nh;
     102             : 
     103             : struct gw_family_t {
     104             :         uint16_t filler;
     105             :         uint16_t family;
     106             :         union g_addr gate;
     107             : };
     108             : 
     109             : static const char ipv4_ll_buf[16] = "169.254.0.1";
     110             : static struct in_addr ipv4_ll;
     111             : 
     112             : /* Is this a ipv4 over ipv6 route? */
     113           0 : static bool is_route_v4_over_v6(unsigned char rtm_family,
     114             :                                 enum nexthop_types_t nexthop_type)
     115             : {
     116           0 :         if (rtm_family == AF_INET
     117           0 :             && (nexthop_type == NEXTHOP_TYPE_IPV6
     118           0 :                 || nexthop_type == NEXTHOP_TYPE_IPV6_IFINDEX))
     119           0 :                 return true;
     120             : 
     121             :         return false;
     122             : }
     123             : 
     124             : /* Helper to control use of kernel-level nexthop ids */
     125         104 : static bool kernel_nexthops_supported(void)
     126             : {
     127         104 :         return (supports_nh && !vrf_is_backend_netns()
     128         208 :                 && zebra_nhg_kernel_nexthops_enabled());
     129             : }
     130             : 
     131             : /*
     132             :  * Some people may only want to use NHGs created by protos and not
     133             :  * implicitly created by Zebra. This check accounts for that.
     134             :  */
     135          54 : static bool proto_nexthops_only(void)
     136             : {
     137           4 :         return zebra_nhg_proto_nexthops_only();
     138             : }
     139             : 
     140             : /* Is this a proto created NHG? */
     141           0 : static bool is_proto_nhg(uint32_t id, int type)
     142             : {
     143             :         /* If type is available, use it as the source of truth */
     144           0 :         if (type) {
     145           0 :                 if (type != ZEBRA_ROUTE_NHG)
     146             :                         return true;
     147             :                 return false;
     148             :         }
     149             : 
     150           0 :         if (id >= ZEBRA_NHG_PROTO_LOWER)
     151             :                 return true;
     152             : 
     153             :         return false;
     154             : }
     155             : 
     156             : /*
     157             :  * The ipv4_ll data structure is used for all 5549
     158             :  * additions to the kernel.  Let's figure out the
     159             :  * correct value one time instead for every
     160             :  * install/remove of a 5549 type route
     161             :  */
     162           4 : void rt_netlink_init(void)
     163             : {
     164           4 :         inet_pton(AF_INET, ipv4_ll_buf, &ipv4_ll);
     165           4 : }
     166             : 
     167             : /*
     168             :  * Mapping from dataplane neighbor flags to netlink flags
     169             :  */
     170           0 : static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags)
     171             : {
     172           0 :         uint8_t flags = 0;
     173             : 
     174           0 :         if (dplane_flags & DPLANE_NTF_EXT_LEARNED)
     175           0 :                 flags |= NTF_EXT_LEARNED;
     176           0 :         if (dplane_flags & DPLANE_NTF_ROUTER)
     177           0 :                 flags |= NTF_ROUTER;
     178           0 :         if (dplane_flags & DPLANE_NTF_USE)
     179           0 :                 flags |= NTF_USE;
     180             : 
     181           0 :         return flags;
     182             : }
     183             : 
     184             : /*
     185             :  * Mapping from dataplane neighbor state to netlink state
     186             :  */
     187           0 : static uint16_t neigh_state_to_netlink(uint16_t dplane_state)
     188             : {
     189           0 :         uint16_t state = 0;
     190             : 
     191           0 :         if (dplane_state & DPLANE_NUD_REACHABLE)
     192           0 :                 state |= NUD_REACHABLE;
     193           0 :         if (dplane_state & DPLANE_NUD_STALE)
     194           0 :                 state |= NUD_STALE;
     195           0 :         if (dplane_state & DPLANE_NUD_NOARP)
     196           0 :                 state |= NUD_NOARP;
     197           0 :         if (dplane_state & DPLANE_NUD_PROBE)
     198           0 :                 state |= NUD_PROBE;
     199           0 :         if (dplane_state & DPLANE_NUD_INCOMPLETE)
     200           0 :                 state |= NUD_INCOMPLETE;
     201           0 :         if (dplane_state & DPLANE_NUD_PERMANENT)
     202           0 :                 state |= NUD_PERMANENT;
     203           0 :         if (dplane_state & DPLANE_NUD_FAILED)
     204           0 :                 state |= NUD_FAILED;
     205             : 
     206           0 :         return state;
     207             : }
     208             : 
     209             : 
     210           0 : static inline bool is_selfroute(int proto)
     211             : {
     212           0 :         if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF)
     213           0 :             || (proto == RTPROT_ZSTATIC) || (proto == RTPROT_ZEBRA)
     214           0 :             || (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)
     215           0 :             || (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
     216           0 :             || (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
     217           0 :             || (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)
     218           0 :             || (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)
     219           0 :             || (proto == RTPROT_SRTE)) {
     220           0 :                 return true;
     221             :         }
     222             : 
     223             :         return false;
     224             : }
     225             : 
     226          37 : int zebra2proto(int proto)
     227             : {
     228          37 :         switch (proto) {
     229             :         case ZEBRA_ROUTE_BABEL:
     230             :                 proto = RTPROT_BABEL;
     231             :                 break;
     232           7 :         case ZEBRA_ROUTE_BGP:
     233           7 :                 proto = RTPROT_BGP;
     234           7 :                 break;
     235           0 :         case ZEBRA_ROUTE_OSPF:
     236             :         case ZEBRA_ROUTE_OSPF6:
     237           0 :                 proto = RTPROT_OSPF;
     238           0 :                 break;
     239           0 :         case ZEBRA_ROUTE_STATIC:
     240           0 :                 proto = RTPROT_ZSTATIC;
     241           0 :                 break;
     242           0 :         case ZEBRA_ROUTE_ISIS:
     243           0 :                 proto = RTPROT_ISIS;
     244           0 :                 break;
     245           0 :         case ZEBRA_ROUTE_RIP:
     246           0 :                 proto = RTPROT_RIP;
     247           0 :                 break;
     248           0 :         case ZEBRA_ROUTE_RIPNG:
     249           0 :                 proto = RTPROT_RIPNG;
     250           0 :                 break;
     251           0 :         case ZEBRA_ROUTE_NHRP:
     252           0 :                 proto = RTPROT_NHRP;
     253           0 :                 break;
     254           0 :         case ZEBRA_ROUTE_EIGRP:
     255           0 :                 proto = RTPROT_EIGRP;
     256           0 :                 break;
     257           0 :         case ZEBRA_ROUTE_LDP:
     258           0 :                 proto = RTPROT_LDP;
     259           0 :                 break;
     260           0 :         case ZEBRA_ROUTE_SHARP:
     261           0 :                 proto = RTPROT_SHARP;
     262           0 :                 break;
     263           0 :         case ZEBRA_ROUTE_PBR:
     264           0 :                 proto = RTPROT_PBR;
     265           0 :                 break;
     266           0 :         case ZEBRA_ROUTE_OPENFABRIC:
     267           0 :                 proto = RTPROT_OPENFABRIC;
     268           0 :                 break;
     269           0 :         case ZEBRA_ROUTE_SRTE:
     270           0 :                 proto = RTPROT_SRTE;
     271           0 :                 break;
     272             :         case ZEBRA_ROUTE_TABLE:
     273             :         case ZEBRA_ROUTE_NHG:
     274          30 :                 proto = RTPROT_ZEBRA;
     275             :                 break;
     276           0 :         case ZEBRA_ROUTE_CONNECT:
     277             :         case ZEBRA_ROUTE_KERNEL:
     278           0 :                 proto = RTPROT_KERNEL;
     279           0 :                 break;
     280           0 :         default:
     281             :                 /*
     282             :                  * When a user adds a new protocol this will show up
     283             :                  * to let them know to do something about it.  This
     284             :                  * is intentionally a warn because we should see
     285             :                  * this as part of development of a new protocol
     286             :                  */
     287           0 :                 zlog_debug(
     288             :                         "%s: Please add this protocol(%d) to proper rt_netlink.c handling",
     289             :                         __func__, proto);
     290           0 :                 proto = RTPROT_ZEBRA;
     291           0 :                 break;
     292             :         }
     293             : 
     294          37 :         return proto;
     295             : }
     296             : 
     297           0 : static inline int proto2zebra(int proto, int family, bool is_nexthop)
     298             : {
     299           0 :         switch (proto) {
     300             :         case RTPROT_BABEL:
     301             :                 proto = ZEBRA_ROUTE_BABEL;
     302             :                 break;
     303           0 :         case RTPROT_BGP:
     304           0 :                 proto = ZEBRA_ROUTE_BGP;
     305           0 :                 break;
     306           0 :         case RTPROT_OSPF:
     307           0 :                 proto = (family == AF_INET) ? ZEBRA_ROUTE_OSPF
     308           0 :                                             : ZEBRA_ROUTE_OSPF6;
     309             :                 break;
     310           0 :         case RTPROT_ISIS:
     311           0 :                 proto = ZEBRA_ROUTE_ISIS;
     312           0 :                 break;
     313           0 :         case RTPROT_RIP:
     314           0 :                 proto = ZEBRA_ROUTE_RIP;
     315           0 :                 break;
     316           0 :         case RTPROT_RIPNG:
     317           0 :                 proto = ZEBRA_ROUTE_RIPNG;
     318           0 :                 break;
     319           0 :         case RTPROT_NHRP:
     320           0 :                 proto = ZEBRA_ROUTE_NHRP;
     321           0 :                 break;
     322           0 :         case RTPROT_EIGRP:
     323           0 :                 proto = ZEBRA_ROUTE_EIGRP;
     324           0 :                 break;
     325           0 :         case RTPROT_LDP:
     326           0 :                 proto = ZEBRA_ROUTE_LDP;
     327           0 :                 break;
     328           0 :         case RTPROT_STATIC:
     329             :         case RTPROT_ZSTATIC:
     330           0 :                 proto = ZEBRA_ROUTE_STATIC;
     331           0 :                 break;
     332           0 :         case RTPROT_SHARP:
     333           0 :                 proto = ZEBRA_ROUTE_SHARP;
     334           0 :                 break;
     335           0 :         case RTPROT_PBR:
     336           0 :                 proto = ZEBRA_ROUTE_PBR;
     337           0 :                 break;
     338           0 :         case RTPROT_OPENFABRIC:
     339           0 :                 proto = ZEBRA_ROUTE_OPENFABRIC;
     340           0 :                 break;
     341           0 :         case RTPROT_SRTE:
     342           0 :                 proto = ZEBRA_ROUTE_SRTE;
     343           0 :                 break;
     344             :         case RTPROT_UNSPEC:
     345             :         case RTPROT_REDIRECT:
     346             :         case RTPROT_KERNEL:
     347             :         case RTPROT_BOOT:
     348             :         case RTPROT_GATED:
     349             :         case RTPROT_RA:
     350             :         case RTPROT_MRT:
     351             :         case RTPROT_BIRD:
     352             :         case RTPROT_DNROUTED:
     353             :         case RTPROT_XORP:
     354             :         case RTPROT_NTK:
     355             :         case RTPROT_MROUTED:
     356             :         case RTPROT_KEEPALIVED:
     357             :         case RTPROT_OPENR:
     358           0 :                 proto = ZEBRA_ROUTE_KERNEL;
     359             :                 break;
     360           0 :         case RTPROT_ZEBRA:
     361           0 :                 if (is_nexthop) {
     362             :                         proto = ZEBRA_ROUTE_NHG;
     363             :                         break;
     364             :                 }
     365             :                 /* Intentional fall thru */
     366             :         default:
     367             :                 /*
     368             :                  * When a user adds a new protocol this will show up
     369             :                  * to let them know to do something about it.  This
     370             :                  * is intentionally a warn because we should see
     371             :                  * this as part of development of a new protocol
     372             :                  */
     373           0 :                 zlog_debug(
     374             :                         "%s: Please add this protocol(%d) to proper rt_netlink.c handling",
     375             :                         __func__, proto);
     376           0 :                 proto = ZEBRA_ROUTE_KERNEL;
     377           0 :                 break;
     378             :         }
     379           0 :         return proto;
     380             : }
     381             : 
     382             : /*
     383             : Pending: create an efficient table_id (in a tree/hash) based lookup)
     384             :  */
     385           0 : vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
     386             : {
     387           0 :         struct vrf *vrf;
     388           0 :         struct zebra_vrf *zvrf;
     389             : 
     390           0 :         RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
     391           0 :                 zvrf = vrf->info;
     392           0 :                 if (zvrf == NULL)
     393           0 :                         continue;
     394             :                 /* case vrf with netns : match the netnsid */
     395           0 :                 if (vrf_is_backend_netns()) {
     396           0 :                         if (ns_id == zvrf_id(zvrf))
     397           0 :                                 return zvrf_id(zvrf);
     398             :                 } else {
     399             :                         /* VRF is VRF_BACKEND_VRF_LITE */
     400           0 :                         if (zvrf->table_id != table_id)
     401           0 :                                 continue;
     402           0 :                         return zvrf_id(zvrf);
     403             :                 }
     404             :         }
     405             : 
     406             :         return VRF_DEFAULT;
     407             : }
     408             : 
     409             : /**
     410             :  * @parse_encap_mpls() - Parses encapsulated mpls attributes
     411             :  * @tb:         Pointer to rtattr to look for nested items in.
     412             :  * @labels:     Pointer to store labels in.
     413             :  *
     414             :  * Return:      Number of mpls labels found.
     415             :  */
     416           0 : static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels)
     417             : {
     418           0 :         struct rtattr *tb_encap[MPLS_IPTUNNEL_MAX + 1] = {0};
     419           0 :         mpls_lse_t *lses = NULL;
     420           0 :         int num_labels = 0;
     421           0 :         uint32_t ttl = 0;
     422           0 :         uint32_t bos = 0;
     423           0 :         uint32_t exp = 0;
     424           0 :         mpls_label_t label = 0;
     425             : 
     426           0 :         netlink_parse_rtattr_nested(tb_encap, MPLS_IPTUNNEL_MAX, tb);
     427           0 :         lses = (mpls_lse_t *)RTA_DATA(tb_encap[MPLS_IPTUNNEL_DST]);
     428           0 :         while (!bos && num_labels < MPLS_MAX_LABELS) {
     429           0 :                 mpls_lse_decode(lses[num_labels], &label, &ttl, &exp, &bos);
     430           0 :                 labels[num_labels++] = label;
     431             :         }
     432             : 
     433           0 :         return num_labels;
     434             : }
     435             : 
     436             : static enum seg6local_action_t
     437           0 : parse_encap_seg6local(struct rtattr *tb,
     438             :                       struct seg6local_context *ctx)
     439             : {
     440           0 :         struct rtattr *tb_encap[SEG6_LOCAL_MAX + 1] = {};
     441           0 :         enum seg6local_action_t act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
     442             : 
     443           0 :         netlink_parse_rtattr_nested(tb_encap, SEG6_LOCAL_MAX, tb);
     444             : 
     445           0 :         if (tb_encap[SEG6_LOCAL_ACTION])
     446           0 :                 act = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_ACTION]);
     447             : 
     448           0 :         if (tb_encap[SEG6_LOCAL_NH4])
     449           0 :                 ctx->nh4 = *(struct in_addr *)RTA_DATA(
     450             :                                 tb_encap[SEG6_LOCAL_NH4]);
     451             : 
     452           0 :         if (tb_encap[SEG6_LOCAL_NH6])
     453           0 :                 ctx->nh6 = *(struct in6_addr *)RTA_DATA(
     454             :                                 tb_encap[SEG6_LOCAL_NH6]);
     455             : 
     456           0 :         if (tb_encap[SEG6_LOCAL_TABLE])
     457           0 :                 ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_TABLE]);
     458             : 
     459           0 :         if (tb_encap[SEG6_LOCAL_VRFTABLE])
     460           0 :                 ctx->table =
     461             :                         *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]);
     462             : 
     463           0 :         return act;
     464             : }
     465             : 
     466           0 : static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs)
     467             : {
     468           0 :         struct rtattr *tb_encap[SEG6_IPTUNNEL_MAX + 1] = {};
     469           0 :         struct seg6_iptunnel_encap *ipt = NULL;
     470           0 :         struct in6_addr *segments = NULL;
     471             : 
     472           0 :         netlink_parse_rtattr_nested(tb_encap, SEG6_IPTUNNEL_MAX, tb);
     473             : 
     474             :         /*
     475             :          * TODO: It's not support multiple SID list.
     476             :          */
     477           0 :         if (tb_encap[SEG6_IPTUNNEL_SRH]) {
     478           0 :                 ipt = (struct seg6_iptunnel_encap *)
     479             :                         RTA_DATA(tb_encap[SEG6_IPTUNNEL_SRH]);
     480           0 :                 segments = ipt->srh[0].segments;
     481           0 :                 *segs = segments[0];
     482           0 :                 return 1;
     483             :         }
     484             : 
     485             :         return 0;
     486             : }
     487             : 
     488             : 
     489             : static struct nexthop
     490           0 : parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
     491             :                       enum blackhole_type bh_type, int index, void *prefsrc,
     492             :                       void *gate, afi_t afi, vrf_id_t vrf_id)
     493             : {
     494           0 :         struct interface *ifp = NULL;
     495           0 :         struct nexthop nh = {0};
     496           0 :         mpls_label_t labels[MPLS_MAX_LABELS] = {0};
     497           0 :         int num_labels = 0;
     498           0 :         enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
     499           0 :         struct seg6local_context seg6l_ctx = {};
     500           0 :         struct in6_addr seg6_segs = {};
     501           0 :         int num_segs = 0;
     502             : 
     503           0 :         vrf_id_t nh_vrf_id = vrf_id;
     504           0 :         size_t sz = (afi == AFI_IP) ? 4 : 16;
     505             : 
     506           0 :         if (bh_type == BLACKHOLE_UNSPEC) {
     507           0 :                 if (index && !gate)
     508           0 :                         nh.type = NEXTHOP_TYPE_IFINDEX;
     509           0 :                 else if (index && gate)
     510           0 :                         nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4_IFINDEX
     511           0 :                                                   : NEXTHOP_TYPE_IPV6_IFINDEX;
     512           0 :                 else if (!index && gate)
     513           0 :                         nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4
     514           0 :                                                   : NEXTHOP_TYPE_IPV6;
     515             :                 else {
     516           0 :                         nh.type = NEXTHOP_TYPE_BLACKHOLE;
     517           0 :                         nh.bh_type = bh_type;
     518             :                 }
     519             :         } else {
     520           0 :                 nh.type = NEXTHOP_TYPE_BLACKHOLE;
     521           0 :                 nh.bh_type = bh_type;
     522             :         }
     523           0 :         nh.ifindex = index;
     524           0 :         if (prefsrc)
     525           0 :                 memcpy(&nh.src, prefsrc, sz);
     526           0 :         if (gate)
     527           0 :                 memcpy(&nh.gate, gate, sz);
     528             : 
     529           0 :         if (index) {
     530           0 :                 ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), index);
     531           0 :                 if (ifp)
     532           0 :                         nh_vrf_id = ifp->vrf->vrf_id;
     533             :         }
     534           0 :         nh.vrf_id = nh_vrf_id;
     535             : 
     536           0 :         if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
     537           0 :             && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
     538             :                        == LWTUNNEL_ENCAP_MPLS) {
     539           0 :                 num_labels = parse_encap_mpls(tb[RTA_ENCAP], labels);
     540             :         }
     541           0 :         if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
     542           0 :             && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
     543             :                        == LWTUNNEL_ENCAP_SEG6_LOCAL) {
     544           0 :                 seg6l_act = parse_encap_seg6local(tb[RTA_ENCAP], &seg6l_ctx);
     545             :         }
     546           0 :         if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
     547           0 :             && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
     548             :                        == LWTUNNEL_ENCAP_SEG6) {
     549           0 :                 num_segs = parse_encap_seg6(tb[RTA_ENCAP], &seg6_segs);
     550             :         }
     551             : 
     552           0 :         if (rtm->rtm_flags & RTNH_F_ONLINK)
     553           0 :                 SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
     554             : 
     555           0 :         if (rtm->rtm_flags & RTNH_F_LINKDOWN)
     556           0 :                 SET_FLAG(nh.flags, NEXTHOP_FLAG_LINKDOWN);
     557             : 
     558           0 :         if (num_labels)
     559           0 :                 nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels);
     560             : 
     561           0 :         if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
     562           0 :                 nexthop_add_srv6_seg6local(&nh, seg6l_act, &seg6l_ctx);
     563             : 
     564           0 :         if (num_segs)
     565           0 :                 nexthop_add_srv6_seg6(&nh, &seg6_segs);
     566             : 
     567           0 :         return nh;
     568             : }
     569             : 
     570           0 : static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id,
     571             :                                                 struct nexthop_group *ng,
     572             :                                                 struct rtmsg *rtm,
     573             :                                                 struct rtnexthop *rtnh,
     574             :                                                 struct rtattr **tb,
     575             :                                                 void *prefsrc, vrf_id_t vrf_id)
     576             : {
     577           0 :         void *gate = NULL;
     578           0 :         struct interface *ifp = NULL;
     579           0 :         int index = 0;
     580             :         /* MPLS labels */
     581           0 :         mpls_label_t labels[MPLS_MAX_LABELS] = {0};
     582           0 :         int num_labels = 0;
     583           0 :         enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
     584           0 :         struct seg6local_context seg6l_ctx = {};
     585           0 :         struct in6_addr seg6_segs = {};
     586           0 :         int num_segs = 0;
     587           0 :         struct rtattr *rtnh_tb[RTA_MAX + 1] = {};
     588             : 
     589           0 :         int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
     590           0 :         vrf_id_t nh_vrf_id = vrf_id;
     591             : 
     592           0 :         for (;;) {
     593           0 :                 struct nexthop *nh = NULL;
     594             : 
     595           0 :                 if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len)
     596             :                         break;
     597             : 
     598           0 :                 index = rtnh->rtnh_ifindex;
     599           0 :                 if (index) {
     600             :                         /*
     601             :                          * Yes we are looking this up
     602             :                          * for every nexthop and just
     603             :                          * using the last one looked
     604             :                          * up right now
     605             :                          */
     606           0 :                         ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
     607             :                                                         index);
     608           0 :                         if (ifp)
     609           0 :                                 nh_vrf_id = ifp->vrf->vrf_id;
     610             :                         else {
     611           0 :                                 flog_warn(
     612             :                                         EC_ZEBRA_UNKNOWN_INTERFACE,
     613             :                                         "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
     614             :                                         __func__, index);
     615           0 :                                 nh_vrf_id = VRF_DEFAULT;
     616             :                         }
     617             :                 } else
     618             :                         nh_vrf_id = vrf_id;
     619             : 
     620           0 :                 if (rtnh->rtnh_len > sizeof(*rtnh)) {
     621           0 :                         netlink_parse_rtattr(rtnh_tb, RTA_MAX, RTNH_DATA(rtnh),
     622           0 :                                              rtnh->rtnh_len - sizeof(*rtnh));
     623           0 :                         if (rtnh_tb[RTA_GATEWAY])
     624           0 :                                 gate = RTA_DATA(rtnh_tb[RTA_GATEWAY]);
     625           0 :                         if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
     626           0 :                             && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
     627             :                                        == LWTUNNEL_ENCAP_MPLS) {
     628           0 :                                 num_labels = parse_encap_mpls(
     629             :                                         rtnh_tb[RTA_ENCAP], labels);
     630             :                         }
     631           0 :                         if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
     632           0 :                             && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
     633             :                                        == LWTUNNEL_ENCAP_SEG6_LOCAL) {
     634           0 :                                 seg6l_act = parse_encap_seg6local(
     635             :                                         rtnh_tb[RTA_ENCAP], &seg6l_ctx);
     636             :                         }
     637           0 :                         if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
     638           0 :                             && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
     639             :                                        == LWTUNNEL_ENCAP_SEG6) {
     640           0 :                                 num_segs = parse_encap_seg6(rtnh_tb[RTA_ENCAP],
     641             :                                                            &seg6_segs);
     642             :                         }
     643             :                 }
     644             : 
     645           0 :                 if (gate && rtm->rtm_family == AF_INET) {
     646           0 :                         if (index)
     647           0 :                                 nh = nexthop_from_ipv4_ifindex(
     648             :                                         gate, prefsrc, index, nh_vrf_id);
     649             :                         else
     650           0 :                                 nh = nexthop_from_ipv4(gate, prefsrc,
     651             :                                                        nh_vrf_id);
     652           0 :                 } else if (gate && rtm->rtm_family == AF_INET6) {
     653           0 :                         if (index)
     654           0 :                                 nh = nexthop_from_ipv6_ifindex(
     655             :                                         gate, index, nh_vrf_id);
     656             :                         else
     657           0 :                                 nh = nexthop_from_ipv6(gate, nh_vrf_id);
     658             :                 } else
     659           0 :                         nh = nexthop_from_ifindex(index, nh_vrf_id);
     660             : 
     661           0 :                 if (nh) {
     662           0 :                         nh->weight = rtnh->rtnh_hops + 1;
     663             : 
     664           0 :                         if (num_labels)
     665           0 :                                 nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
     666             :                                                    num_labels, labels);
     667             : 
     668           0 :                         if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
     669           0 :                                 nexthop_add_srv6_seg6local(nh, seg6l_act,
     670             :                                                            &seg6l_ctx);
     671             : 
     672           0 :                         if (num_segs)
     673           0 :                                 nexthop_add_srv6_seg6(nh, &seg6_segs);
     674             : 
     675           0 :                         if (rtnh->rtnh_flags & RTNH_F_ONLINK)
     676           0 :                                 SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK);
     677             : 
     678             :                         /* Add to temporary list */
     679           0 :                         nexthop_group_add_sorted(ng, nh);
     680             :                 }
     681             : 
     682           0 :                 if (rtnh->rtnh_len == 0)
     683             :                         break;
     684             : 
     685           0 :                 len -= NLMSG_ALIGN(rtnh->rtnh_len);
     686           0 :                 rtnh = RTNH_NEXT(rtnh);
     687             :         }
     688             : 
     689           0 :         uint8_t nhop_num = nexthop_group_nexthop_num(ng);
     690             : 
     691           0 :         return nhop_num;
     692             : }
     693             : 
     694             : /* Looking up routing table by netlink interface. */
     695          78 : int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
     696             :                                                ns_id_t ns_id, int startup,
     697             :                                                struct zebra_dplane_ctx *ctx)
     698             : {
     699          78 :         int len;
     700          78 :         struct rtmsg *rtm;
     701          78 :         struct rtattr *tb[RTA_MAX + 1];
     702          78 :         uint32_t flags = 0;
     703          78 :         struct prefix p;
     704          78 :         struct prefix_ipv6 src_p = {};
     705          78 :         vrf_id_t vrf_id;
     706          78 :         bool selfroute;
     707             : 
     708          78 :         char anyaddr[16] = {0};
     709             : 
     710          78 :         int proto = ZEBRA_ROUTE_KERNEL;
     711          78 :         int index = 0;
     712          78 :         int table;
     713          78 :         int metric = 0;
     714          78 :         uint32_t mtu = 0;
     715          78 :         uint8_t distance = 0;
     716          78 :         route_tag_t tag = 0;
     717          78 :         uint32_t nhe_id = 0;
     718             : 
     719          78 :         void *dest = NULL;
     720          78 :         void *gate = NULL;
     721          78 :         void *prefsrc = NULL; /* IPv4 preferred source host address */
     722          78 :         void *src = NULL;     /* IPv6 srcdest   source prefix */
     723          78 :         enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
     724             : 
     725          78 :         frrtrace(3, frr_zebra, netlink_route_change_read_unicast, h, ns_id,
     726             :                  startup);
     727             : 
     728          78 :         rtm = NLMSG_DATA(h);
     729             : 
     730          78 :         if (startup && h->nlmsg_type != RTM_NEWROUTE)
     731             :                 return 0;
     732          78 :         switch (rtm->rtm_type) {
     733             :         case RTN_UNICAST:
     734             :                 break;
     735           0 :         case RTN_BLACKHOLE:
     736           0 :                 bh_type = BLACKHOLE_NULL;
     737           0 :                 break;
     738           0 :         case RTN_UNREACHABLE:
     739           0 :                 bh_type = BLACKHOLE_REJECT;
     740           0 :                 break;
     741           0 :         case RTN_PROHIBIT:
     742           0 :                 bh_type = BLACKHOLE_ADMINPROHIB;
     743           0 :                 break;
     744          59 :         default:
     745          59 :                 if (IS_ZEBRA_DEBUG_KERNEL)
     746           0 :                         zlog_debug("Route rtm_type: %s(%d) intentionally ignoring",
     747             :                                    nl_rttype_to_str(rtm->rtm_type),
     748             :                                    rtm->rtm_type);
     749             :                 return 0;
     750             :         }
     751             : 
     752          19 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
     753          19 :         if (len < 0) {
     754           0 :                 zlog_err(
     755             :                         "%s: Message received from netlink is of a broken size %d %zu",
     756             :                         __func__, h->nlmsg_len,
     757             :                         (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
     758           0 :                 return -1;
     759             :         }
     760             : 
     761          19 :         netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
     762             : 
     763          19 :         if (rtm->rtm_flags & RTM_F_CLONED)
     764             :                 return 0;
     765          19 :         if (rtm->rtm_protocol == RTPROT_REDIRECT)
     766             :                 return 0;
     767          19 :         if (rtm->rtm_protocol == RTPROT_KERNEL)
     768             :                 return 0;
     769             : 
     770           0 :         selfroute = is_selfroute(rtm->rtm_protocol);
     771             : 
     772           0 :         if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE &&
     773           0 :             !zrouter.asic_offloaded && !ctx) {
     774           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
     775           0 :                         zlog_debug("Route type: %d Received that we think we have originated, ignoring",
     776             :                                    rtm->rtm_protocol);
     777           0 :                 return 0;
     778             :         }
     779             : 
     780             :         /* We don't care about change notifications for the MPLS table. */
     781             :         /* TODO: Revisit this. */
     782           0 :         if (rtm->rtm_family == AF_MPLS)
     783             :                 return 0;
     784             : 
     785             :         /* Table corresponding to route. */
     786           0 :         if (tb[RTA_TABLE])
     787           0 :                 table = *(int *)RTA_DATA(tb[RTA_TABLE]);
     788             :         else
     789           0 :                 table = rtm->rtm_table;
     790             : 
     791             :         /* Map to VRF */
     792           0 :         vrf_id = vrf_lookup_by_table(table, ns_id);
     793           0 :         if (vrf_id == VRF_DEFAULT) {
     794           0 :                 if (!is_zebra_valid_kernel_table(table)
     795           0 :                     && !is_zebra_main_routing_table(table))
     796             :                         return 0;
     797             :         }
     798             : 
     799           0 :         if (rtm->rtm_flags & RTM_F_TRAP)
     800           0 :                 flags |= ZEBRA_FLAG_TRAPPED;
     801           0 :         if (rtm->rtm_flags & RTM_F_OFFLOAD)
     802           0 :                 flags |= ZEBRA_FLAG_OFFLOADED;
     803           0 :         if (rtm->rtm_flags & RTM_F_OFFLOAD_FAILED)
     804           0 :                 flags |= ZEBRA_FLAG_OFFLOAD_FAILED;
     805             : 
     806           0 :         if (h->nlmsg_flags & NLM_F_APPEND)
     807           0 :                 flags |= ZEBRA_FLAG_OUTOFSYNC;
     808             : 
     809             :         /* Route which inserted by Zebra. */
     810           0 :         if (selfroute) {
     811           0 :                 flags |= ZEBRA_FLAG_SELFROUTE;
     812           0 :                 proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
     813             :         }
     814           0 :         if (tb[RTA_OIF])
     815           0 :                 index = *(int *)RTA_DATA(tb[RTA_OIF]);
     816             : 
     817           0 :         if (tb[RTA_DST])
     818           0 :                 dest = RTA_DATA(tb[RTA_DST]);
     819             :         else
     820             :                 dest = anyaddr;
     821             : 
     822           0 :         if (tb[RTA_SRC])
     823           0 :                 src = RTA_DATA(tb[RTA_SRC]);
     824             :         else
     825             :                 src = anyaddr;
     826             : 
     827           0 :         if (tb[RTA_PREFSRC])
     828           0 :                 prefsrc = RTA_DATA(tb[RTA_PREFSRC]);
     829             : 
     830           0 :         if (tb[RTA_GATEWAY])
     831           0 :                 gate = RTA_DATA(tb[RTA_GATEWAY]);
     832             : 
     833           0 :         if (tb[RTA_NH_ID])
     834           0 :                 nhe_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]);
     835             : 
     836           0 :         if (tb[RTA_PRIORITY])
     837           0 :                 metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]);
     838             : 
     839             : #if defined(SUPPORT_REALMS)
     840             :         if (tb[RTA_FLOW])
     841             :                 tag = *(uint32_t *)RTA_DATA(tb[RTA_FLOW]);
     842             : #endif
     843             : 
     844           0 :         if (tb[RTA_METRICS]) {
     845           0 :                 struct rtattr *mxrta[RTAX_MAX + 1];
     846             : 
     847           0 :                 netlink_parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
     848           0 :                                      RTA_PAYLOAD(tb[RTA_METRICS]));
     849             : 
     850           0 :                 if (mxrta[RTAX_MTU])
     851           0 :                         mtu = *(uint32_t *)RTA_DATA(mxrta[RTAX_MTU]);
     852             :         }
     853             : 
     854           0 :         if (rtm->rtm_family == AF_INET) {
     855           0 :                 p.family = AF_INET;
     856           0 :                 if (rtm->rtm_dst_len > IPV4_MAX_BITLEN) {
     857           0 :                         zlog_err(
     858             :                                 "Invalid destination prefix length: %u received from kernel route change",
     859             :                                 rtm->rtm_dst_len);
     860           0 :                         return -1;
     861             :                 }
     862           0 :                 memcpy(&p.u.prefix4, dest, 4);
     863           0 :                 p.prefixlen = rtm->rtm_dst_len;
     864             : 
     865           0 :                 if (rtm->rtm_src_len != 0) {
     866           0 :                         flog_warn(
     867             :                                 EC_ZEBRA_UNSUPPORTED_V4_SRCDEST,
     868             :                                 "unsupported IPv4 sourcedest route (dest %pFX vrf %u)",
     869             :                                 &p, vrf_id);
     870           0 :                         return 0;
     871             :                 }
     872             : 
     873             :                 /* Force debug below to not display anything for source */
     874           0 :                 src_p.prefixlen = 0;
     875           0 :         } else if (rtm->rtm_family == AF_INET6) {
     876           0 :                 p.family = AF_INET6;
     877           0 :                 if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) {
     878           0 :                         zlog_err(
     879             :                                 "Invalid destination prefix length: %u received from kernel route change",
     880             :                                 rtm->rtm_dst_len);
     881           0 :                         return -1;
     882             :                 }
     883           0 :                 memcpy(&p.u.prefix6, dest, 16);
     884           0 :                 p.prefixlen = rtm->rtm_dst_len;
     885             : 
     886           0 :                 src_p.family = AF_INET6;
     887           0 :                 if (rtm->rtm_src_len > IPV6_MAX_BITLEN) {
     888           0 :                         zlog_err(
     889             :                                 "Invalid source prefix length: %u received from kernel route change",
     890             :                                 rtm->rtm_src_len);
     891           0 :                         return -1;
     892             :                 }
     893           0 :                 memcpy(&src_p.prefix, src, 16);
     894           0 :                 src_p.prefixlen = rtm->rtm_src_len;
     895             :         } else {
     896             :                 /* We only handle the AFs we handle... */
     897           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
     898           0 :                         zlog_debug("%s: unknown address-family %u", __func__,
     899             :                                    rtm->rtm_family);
     900           0 :                 return 0;
     901             :         }
     902             : 
     903             :         /*
     904             :          * For ZEBRA_ROUTE_KERNEL types:
     905             :          *
     906             :          * The metric/priority of the route received from the kernel
     907             :          * is a 32 bit number.  We are going to interpret the high
     908             :          * order byte as the Admin Distance and the low order 3 bytes
     909             :          * as the metric.
     910             :          *
     911             :          * This will allow us to do two things:
     912             :          * 1) Allow the creation of kernel routes that can be
     913             :          *    overridden by zebra.
     914             :          * 2) Allow the old behavior for 'most' kernel route types
     915             :          *    if a user enters 'ip route ...' v4 routes get a metric
     916             :          *    of 0 and v6 routes get a metric of 1024.  Both of these
     917             :          *    values will end up with a admin distance of 0, which
     918             :          *    will cause them to win for the purposes of zebra.
     919             :          */
     920           0 :         if (proto == ZEBRA_ROUTE_KERNEL) {
     921           0 :                 distance = (metric >> 24) & 0xFF;
     922           0 :                 metric = (metric & 0x00FFFFFF);
     923             :         }
     924             : 
     925           0 :         if (IS_ZEBRA_DEBUG_KERNEL) {
     926           0 :                 char buf2[PREFIX_STRLEN];
     927             : 
     928           0 :                 zlog_debug(
     929             :                         "%s %pFX%s%s vrf %s(%u) table_id: %u metric: %d Admin Distance: %d",
     930             :                         nl_msg_type_to_str(h->nlmsg_type), &p,
     931             :                         src_p.prefixlen ? " from " : "",
     932             :                         src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2))
     933             :                                         : "",
     934             :                         vrf_id_to_name(vrf_id), vrf_id, table, metric,
     935             :                         distance);
     936             :         }
     937             : 
     938           0 :         afi_t afi = AFI_IP;
     939           0 :         if (rtm->rtm_family == AF_INET6)
     940           0 :                 afi = AFI_IP6;
     941             : 
     942           0 :         if (h->nlmsg_type == RTM_NEWROUTE) {
     943           0 :                 struct route_entry *re;
     944           0 :                 struct nexthop_group *ng = NULL;
     945             : 
     946           0 :                 re = zebra_rib_route_entry_new(vrf_id, proto, 0, flags, nhe_id,
     947             :                                                table, metric, mtu, distance,
     948             :                                                tag);
     949           0 :                 if (!nhe_id)
     950           0 :                         ng = nexthop_group_new();
     951             : 
     952           0 :                 if (!tb[RTA_MULTIPATH]) {
     953           0 :                         struct nexthop *nexthop, nh;
     954             : 
     955           0 :                         if (!nhe_id) {
     956           0 :                                 nh = parse_nexthop_unicast(
     957             :                                         ns_id, rtm, tb, bh_type, index, prefsrc,
     958             :                                         gate, afi, vrf_id);
     959             : 
     960           0 :                                 nexthop = nexthop_new();
     961           0 :                                 *nexthop = nh;
     962           0 :                                 nexthop_group_add_sorted(ng, nexthop);
     963             :                         }
     964             :                 } else {
     965             :                         /* This is a multipath route */
     966           0 :                         struct rtnexthop *rtnh =
     967             :                                 (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
     968             : 
     969           0 :                         if (!nhe_id) {
     970           0 :                                 uint8_t nhop_num;
     971             : 
     972             :                                 /* Use temporary list of nexthops; parse
     973             :                                  * message payload's nexthops.
     974             :                                  */
     975           0 :                                 nhop_num =
     976           0 :                                         parse_multipath_nexthops_unicast(
     977             :                                                 ns_id, ng, rtm, rtnh, tb,
     978             :                                                 prefsrc, vrf_id);
     979             : 
     980           0 :                                 zserv_nexthop_num_warn(
     981             :                                         __func__, (const struct prefix *)&p,
     982             :                                         nhop_num);
     983             : 
     984           0 :                                 if (nhop_num == 0) {
     985           0 :                                         nexthop_group_delete(&ng);
     986           0 :                                         ng = NULL;
     987             :                                 }
     988             :                         }
     989             :                 }
     990           0 :                 if (nhe_id || ng) {
     991           0 :                         dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
     992             :                                                  re, ng, startup, ctx);
     993           0 :                         if (ng)
     994           0 :                                 nexthop_group_delete(&ng);
     995             :                 } else {
     996             :                         /*
     997             :                          * I really don't see how this is possible
     998             :                          * but since we are testing for it let's
     999             :                          * let the end user know why the route
    1000             :                          * that was just received was swallowed
    1001             :                          * up and forgotten
    1002             :                          */
    1003           0 :                         zlog_err(
    1004             :                                 "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel",
    1005             :                                 __func__, &p);
    1006           0 :                         XFREE(MTYPE_RE, re);
    1007             :                 }
    1008             :         } else {
    1009           0 :                 if (ctx) {
    1010           0 :                         zlog_err(
    1011             :                                 "%s: %pFX RTM_DELROUTE received but received a context as well",
    1012             :                                 __func__, &p);
    1013           0 :                         return 0;
    1014             :                 }
    1015             : 
    1016           0 :                 if (nhe_id) {
    1017           0 :                         rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
    1018             :                                    &p, &src_p, NULL, nhe_id, table, metric,
    1019             :                                    distance, true);
    1020             :                 } else {
    1021           0 :                         if (!tb[RTA_MULTIPATH]) {
    1022           0 :                                 struct nexthop nh;
    1023             : 
    1024           0 :                                 nh = parse_nexthop_unicast(
    1025             :                                         ns_id, rtm, tb, bh_type, index, prefsrc,
    1026             :                                         gate, afi, vrf_id);
    1027           0 :                                 rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
    1028             :                                            flags, &p, &src_p, &nh, 0, table,
    1029             :                                            metric, distance, true);
    1030             :                         } else {
    1031             :                                 /* XXX: need to compare the entire list of
    1032             :                                  * nexthops here for NLM_F_APPEND stupidity */
    1033           0 :                                 rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
    1034             :                                            flags, &p, &src_p, NULL, 0, table,
    1035             :                                            metric, distance, true);
    1036             :                         }
    1037             :                 }
    1038             :         }
    1039             : 
    1040             :         return 1;
    1041             : }
    1042             : 
    1043          78 : static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
    1044             :                                              int startup)
    1045             : {
    1046          63 :         return netlink_route_change_read_unicast_internal(h, ns_id, startup,
    1047             :                                                           NULL);
    1048             : }
    1049             : 
    1050             : static struct mcast_route_data *mroute = NULL;
    1051             : 
    1052           0 : static int netlink_route_change_read_multicast(struct nlmsghdr *h,
    1053             :                                                ns_id_t ns_id, int startup)
    1054             : {
    1055           0 :         int len;
    1056           0 :         struct rtmsg *rtm;
    1057           0 :         struct rtattr *tb[RTA_MAX + 1];
    1058           0 :         struct mcast_route_data *m;
    1059           0 :         int iif = 0;
    1060           0 :         int count;
    1061           0 :         int oif[256];
    1062           0 :         int oif_count = 0;
    1063           0 :         char oif_list[256] = "\0";
    1064           0 :         vrf_id_t vrf;
    1065           0 :         int table;
    1066             : 
    1067           0 :         assert(mroute);
    1068           0 :         m = mroute;
    1069             : 
    1070           0 :         rtm = NLMSG_DATA(h);
    1071             : 
    1072           0 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
    1073             : 
    1074           0 :         netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
    1075             : 
    1076           0 :         if (tb[RTA_TABLE])
    1077           0 :                 table = *(int *)RTA_DATA(tb[RTA_TABLE]);
    1078             :         else
    1079           0 :                 table = rtm->rtm_table;
    1080             : 
    1081           0 :         vrf = vrf_lookup_by_table(table, ns_id);
    1082             : 
    1083           0 :         if (tb[RTA_IIF])
    1084           0 :                 iif = *(int *)RTA_DATA(tb[RTA_IIF]);
    1085             : 
    1086           0 :         if (tb[RTA_SRC]) {
    1087           0 :                 if (rtm->rtm_family == RTNL_FAMILY_IPMR)
    1088           0 :                         m->src.ipaddr_v4 =
    1089             :                                 *(struct in_addr *)RTA_DATA(tb[RTA_SRC]);
    1090             :                 else
    1091           0 :                         m->src.ipaddr_v6 =
    1092             :                                 *(struct in6_addr *)RTA_DATA(tb[RTA_SRC]);
    1093             :         }
    1094             : 
    1095           0 :         if (tb[RTA_DST]) {
    1096           0 :                 if (rtm->rtm_family == RTNL_FAMILY_IPMR)
    1097           0 :                         m->grp.ipaddr_v4 =
    1098             :                                 *(struct in_addr *)RTA_DATA(tb[RTA_DST]);
    1099             :                 else
    1100           0 :                         m->grp.ipaddr_v6 =
    1101             :                                 *(struct in6_addr *)RTA_DATA(tb[RTA_DST]);
    1102             :         }
    1103             : 
    1104           0 :         if (tb[RTA_EXPIRES])
    1105           0 :                 m->lastused = *(unsigned long long *)RTA_DATA(tb[RTA_EXPIRES]);
    1106             : 
    1107           0 :         if (tb[RTA_MULTIPATH]) {
    1108           0 :                 struct rtnexthop *rtnh =
    1109             :                         (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
    1110             : 
    1111           0 :                 len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
    1112           0 :                 for (;;) {
    1113           0 :                         if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len)
    1114             :                                 break;
    1115             : 
    1116           0 :                         oif[oif_count] = rtnh->rtnh_ifindex;
    1117           0 :                         oif_count++;
    1118             : 
    1119           0 :                         if (rtnh->rtnh_len == 0)
    1120             :                                 break;
    1121             : 
    1122           0 :                         len -= NLMSG_ALIGN(rtnh->rtnh_len);
    1123           0 :                         rtnh = RTNH_NEXT(rtnh);
    1124             :                 }
    1125             :         }
    1126             : 
    1127           0 :         if (rtm->rtm_family == RTNL_FAMILY_IPMR) {
    1128           0 :                 SET_IPADDR_V4(&m->src);
    1129           0 :                 SET_IPADDR_V4(&m->grp);
    1130           0 :         } else if (rtm->rtm_family == RTNL_FAMILY_IP6MR) {
    1131           0 :                 SET_IPADDR_V6(&m->src);
    1132           0 :                 SET_IPADDR_V6(&m->grp);
    1133             :         } else {
    1134           0 :                 zlog_warn("%s: Invalid rtm_family received", __func__);
    1135           0 :                 return 0;
    1136             :         }
    1137             : 
    1138           0 :         if (IS_ZEBRA_DEBUG_KERNEL) {
    1139           0 :                 struct interface *ifp = NULL;
    1140           0 :                 struct zebra_vrf *zvrf = NULL;
    1141             : 
    1142           0 :                 for (count = 0; count < oif_count; count++) {
    1143           0 :                         ifp = if_lookup_by_index(oif[count], vrf);
    1144           0 :                         char temp[256];
    1145             : 
    1146           0 :                         snprintf(temp, sizeof(temp), "%s(%d) ",
    1147             :                                  ifp ? ifp->name : "Unknown", oif[count]);
    1148           0 :                         strlcat(oif_list, temp, sizeof(oif_list));
    1149             :                 }
    1150           0 :                 zvrf = zebra_vrf_lookup_by_id(vrf);
    1151           0 :                 ifp = if_lookup_by_index(iif, vrf);
    1152           0 :                 zlog_debug(
    1153             :                         "MCAST VRF: %s(%d) %s (%pIA,%pIA) IIF: %s(%d) OIF: %s jiffies: %lld",
    1154             :                         zvrf_name(zvrf), vrf, nl_msg_type_to_str(h->nlmsg_type),
    1155             :                         &m->src, &m->grp, ifp ? ifp->name : "Unknown", iif,
    1156             :                         oif_list, m->lastused);
    1157             :         }
    1158             :         return 0;
    1159             : }
    1160             : 
    1161          15 : int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
    1162             : {
    1163          15 :         int len;
    1164          15 :         struct rtmsg *rtm;
    1165             : 
    1166          15 :         rtm = NLMSG_DATA(h);
    1167             : 
    1168          15 :         if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) {
    1169             :                 /* If this is not route add/delete message print warning. */
    1170           0 :                 zlog_debug("Kernel message: %s NS %u",
    1171             :                            nl_msg_type_to_str(h->nlmsg_type), ns_id);
    1172           0 :                 return 0;
    1173             :         }
    1174             : 
    1175          15 :         switch (rtm->rtm_family) {
    1176             :         case AF_INET:
    1177             :         case AF_INET6:
    1178          15 :                 break;
    1179             : 
    1180             :         case RTNL_FAMILY_IPMR:
    1181             :         case RTNL_FAMILY_IP6MR:
    1182             :                 /* notifications on IPMR are irrelevant to zebra, we only care
    1183             :                  * about responses to RTM_GETROUTE requests we sent.
    1184             :                  */
    1185             :                 return 0;
    1186             : 
    1187           0 :         default:
    1188           0 :                 flog_warn(
    1189             :                         EC_ZEBRA_UNKNOWN_FAMILY,
    1190             :                         "Invalid address family: %u received from kernel route change: %s",
    1191             :                         rtm->rtm_family, nl_msg_type_to_str(h->nlmsg_type));
    1192           0 :                 return 0;
    1193             :         }
    1194             : 
    1195             :         /* Connected route. */
    1196          15 :         if (IS_ZEBRA_DEBUG_KERNEL)
    1197           0 :                 zlog_debug("%s %s %s proto %s NS %u",
    1198             :                            nl_msg_type_to_str(h->nlmsg_type),
    1199             :                            nl_family_to_str(rtm->rtm_family),
    1200             :                            nl_rttype_to_str(rtm->rtm_type),
    1201             :                            nl_rtproto_to_str(rtm->rtm_protocol), ns_id);
    1202             : 
    1203             : 
    1204          15 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
    1205          15 :         if (len < 0) {
    1206           0 :                 zlog_err(
    1207             :                         "%s: Message received from netlink is of a broken size: %d %zu",
    1208             :                         __func__, h->nlmsg_len,
    1209             :                         (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
    1210           0 :                 return -1;
    1211             :         }
    1212             : 
    1213             :         /* these are "magic" kernel-managed *unicast* routes used for
    1214             :          * outputting locally generated multicast traffic (which uses unicast
    1215             :          * handling on Linux because ~reasons~.
    1216             :          */
    1217          15 :         if (rtm->rtm_type == RTN_MULTICAST)
    1218             :                 return 0;
    1219             : 
    1220          15 :         netlink_route_change_read_unicast(h, ns_id, startup);
    1221          15 :         return 0;
    1222             : }
    1223             : 
    1224             : /* Request for specific route information from the kernel */
    1225           8 : static int netlink_request_route(struct zebra_ns *zns, int family, int type)
    1226             : {
    1227           8 :         struct {
    1228             :                 struct nlmsghdr n;
    1229             :                 struct rtmsg rtm;
    1230             :         } req;
    1231             : 
    1232             :         /* Form the request, specifying filter (rtattr) if needed. */
    1233           8 :         memset(&req, 0, sizeof(req));
    1234           8 :         req.n.nlmsg_type = type;
    1235           8 :         req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
    1236           8 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    1237           8 :         req.rtm.rtm_family = family;
    1238             : 
    1239           8 :         return netlink_request(&zns->netlink_cmd, &req);
    1240             : }
    1241             : 
    1242             : /* Routing table read function using netlink interface.  Only called
    1243             :    bootstrap time. */
    1244           4 : int netlink_route_read(struct zebra_ns *zns)
    1245             : {
    1246           4 :         int ret;
    1247           4 :         struct zebra_dplane_info dp_info;
    1248             : 
    1249           4 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    1250             : 
    1251             :         /* Get IPv4 routing table. */
    1252           4 :         ret = netlink_request_route(zns, AF_INET, RTM_GETROUTE);
    1253           4 :         if (ret < 0)
    1254             :                 return ret;
    1255           4 :         ret = netlink_parse_info(netlink_route_change_read_unicast,
    1256             :                                  &zns->netlink_cmd, &dp_info, 0, true);
    1257           4 :         if (ret < 0)
    1258             :                 return ret;
    1259             : 
    1260             :         /* Get IPv6 routing table. */
    1261           4 :         ret = netlink_request_route(zns, AF_INET6, RTM_GETROUTE);
    1262           4 :         if (ret < 0)
    1263             :                 return ret;
    1264           4 :         ret = netlink_parse_info(netlink_route_change_read_unicast,
    1265             :                                  &zns->netlink_cmd, &dp_info, 0, true);
    1266           4 :         if (ret < 0)
    1267             :                 return ret;
    1268             : 
    1269             :         return 0;
    1270             : }
    1271             : 
    1272             : /*
    1273             :  * The function returns true if the gateway info could be added
    1274             :  * to the message, otherwise false is returned.
    1275             :  */
    1276           0 : static bool _netlink_route_add_gateway_info(uint8_t route_family,
    1277             :                                             uint8_t gw_family,
    1278             :                                             struct nlmsghdr *nlmsg,
    1279             :                                             size_t req_size, int bytelen,
    1280             :                                             const struct nexthop *nexthop)
    1281             : {
    1282           0 :         if (route_family == AF_MPLS) {
    1283           0 :                 struct gw_family_t gw_fam;
    1284             : 
    1285           0 :                 gw_fam.family = gw_family;
    1286           0 :                 if (gw_family == AF_INET)
    1287           0 :                         memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen);
    1288             :                 else
    1289           0 :                         memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen);
    1290           0 :                 if (!nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family,
    1291           0 :                                  bytelen + 2))
    1292           0 :                         return false;
    1293             :         } else {
    1294           0 :                 if (!(nexthop->rparent
    1295           0 :                       && IS_MAPPED_IPV6(&nexthop->rparent->gate.ipv6))) {
    1296           0 :                         if (gw_family == AF_INET) {
    1297           0 :                                 if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
    1298           0 :                                                  &nexthop->gate.ipv4, bytelen))
    1299             :                                         return false;
    1300             :                         } else {
    1301           0 :                                 if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
    1302           0 :                                                  &nexthop->gate.ipv6, bytelen))
    1303             :                                         return false;
    1304             :                         }
    1305             :                 }
    1306             :         }
    1307             : 
    1308             :         return true;
    1309             : }
    1310             : 
    1311          30 : static int build_label_stack(struct mpls_label_stack *nh_label,
    1312             :                              mpls_lse_t *out_lse, char *label_buf,
    1313             :                              size_t label_buf_size)
    1314             : {
    1315          30 :         char label_buf1[20];
    1316          30 :         int num_labels = 0;
    1317             : 
    1318          30 :         for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
    1319           0 :                 if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
    1320           0 :                         continue;
    1321             : 
    1322           0 :                 if (IS_ZEBRA_DEBUG_KERNEL) {
    1323           0 :                         if (!num_labels)
    1324           0 :                                 snprintf(label_buf, label_buf_size, "label %u",
    1325             :                                          nh_label->label[i]);
    1326             :                         else {
    1327           0 :                                 snprintf(label_buf1, sizeof(label_buf1), "/%u",
    1328             :                                          nh_label->label[i]);
    1329           0 :                                 strlcat(label_buf, label_buf1, label_buf_size);
    1330             :                         }
    1331             :                 }
    1332             : 
    1333           0 :                 out_lse[num_labels] =
    1334           0 :                         mpls_lse_encode(nh_label->label[i], 0, 0, 0);
    1335           0 :                 num_labels++;
    1336             :         }
    1337             : 
    1338          30 :         return num_labels;
    1339             : }
    1340             : 
    1341           0 : static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
    1342             :                                              struct nlmsghdr *nlmsg,
    1343             :                                              size_t buflen, struct rtmsg *rtmsg,
    1344             :                                              char *label_buf,
    1345             :                                              size_t label_buf_size)
    1346             : {
    1347           0 :         mpls_lse_t out_lse[MPLS_MAX_LABELS];
    1348           0 :         int num_labels;
    1349             : 
    1350             :         /*
    1351             :          * label_buf is *only* currently used within debugging.
    1352             :          * As such when we assign it we are guarding it inside
    1353             :          * a debug test.  If you want to change this make sure
    1354             :          * you fix this assumption
    1355             :          */
    1356           0 :         label_buf[0] = '\0';
    1357             : 
    1358           0 :         num_labels =
    1359           0 :                 build_label_stack(nh_label, out_lse, label_buf, label_buf_size);
    1360             : 
    1361           0 :         if (num_labels) {
    1362             :                 /* Set the BoS bit */
    1363           0 :                 out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
    1364             : 
    1365           0 :                 if (rtmsg->rtm_family == AF_MPLS) {
    1366           0 :                         if (!nl_attr_put(nlmsg, buflen, RTA_NEWDST, &out_lse,
    1367             :                                          num_labels * sizeof(mpls_lse_t)))
    1368             :                                 return false;
    1369             :                 } else {
    1370           0 :                         struct rtattr *nest;
    1371             : 
    1372           0 :                         if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE,
    1373             :                                            LWTUNNEL_ENCAP_MPLS))
    1374             :                                 return false;
    1375             : 
    1376           0 :                         nest = nl_attr_nest(nlmsg, buflen, RTA_ENCAP);
    1377           0 :                         if (!nest)
    1378             :                                 return false;
    1379             : 
    1380           0 :                         if (!nl_attr_put(nlmsg, buflen, MPLS_IPTUNNEL_DST,
    1381             :                                          &out_lse,
    1382             :                                          num_labels * sizeof(mpls_lse_t)))
    1383             :                                 return false;
    1384           0 :                         nl_attr_nest_end(nlmsg, nest);
    1385             :                 }
    1386             :         }
    1387             : 
    1388             :         return true;
    1389             : }
    1390             : 
    1391           0 : static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop,
    1392             :                                               int family,
    1393             :                                               struct nlmsghdr *nlmsg,
    1394             :                                               size_t buflen, int bytelen)
    1395             : {
    1396           0 :         if (family == AF_INET) {
    1397           0 :                 if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
    1398           0 :                         if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
    1399           0 :                                          &nexthop->rmap_src.ipv4, bytelen))
    1400             :                                 return false;
    1401           0 :                 } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
    1402           0 :                         if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
    1403           0 :                                          &nexthop->src.ipv4, bytelen))
    1404             :                                 return false;
    1405             :                 }
    1406           0 :         } else if (family == AF_INET6) {
    1407           0 :                 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
    1408           0 :                         if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
    1409           0 :                                          &nexthop->rmap_src.ipv6, bytelen))
    1410             :                                 return false;
    1411           0 :                 } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) {
    1412           0 :                         if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
    1413           0 :                                          &nexthop->src.ipv6, bytelen))
    1414             :                                 return false;
    1415             :                 }
    1416             :         }
    1417             : 
    1418             :         return true;
    1419             : }
    1420             : 
    1421           0 : static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen,
    1422             :                                   const struct in6_addr *seg)
    1423             : {
    1424           0 :         struct seg6_iptunnel_encap *ipt;
    1425           0 :         struct ipv6_sr_hdr *srh;
    1426           0 :         const size_t srhlen = 24;
    1427             : 
    1428             :         /*
    1429             :          * Caution: Support only SINGLE-SID, not MULTI-SID
    1430             :          * This function only supports the case where segs represents
    1431             :          * a single SID. If you want to extend the SRv6 functionality,
    1432             :          * you should improve the Boundary Check.
    1433             :          * Ex. In case of set a SID-List include multiple-SIDs as an
    1434             :          * argument of the Transit Behavior, we must support variable
    1435             :          * boundary check for buflen.
    1436             :          */
    1437           0 :         if (buflen < (sizeof(struct seg6_iptunnel_encap) +
    1438             :                       sizeof(struct ipv6_sr_hdr) + 16))
    1439             :                 return -1;
    1440             : 
    1441           0 :         memset(buffer, 0, buflen);
    1442             : 
    1443           0 :         ipt = (struct seg6_iptunnel_encap *)buffer;
    1444           0 :         ipt->mode = SEG6_IPTUN_MODE_ENCAP;
    1445           0 :         srh = ipt->srh;
    1446           0 :         srh->hdrlen = (srhlen >> 3) - 1;
    1447           0 :         srh->type = 4;
    1448           0 :         srh->segments_left = 0;
    1449           0 :         srh->first_segment = 0;
    1450           0 :         memcpy(&srh->segments[0], seg, sizeof(struct in6_addr));
    1451             : 
    1452           0 :         return srhlen + 4;
    1453             : }
    1454             : 
    1455             : /* This function takes a nexthop as argument and adds
    1456             :  * the appropriate netlink attributes to an existing
    1457             :  * netlink message.
    1458             :  *
    1459             :  * @param routedesc: Human readable description of route type
    1460             :  *                   (direct/recursive, single-/multipath)
    1461             :  * @param bytelen: Length of addresses in bytes.
    1462             :  * @param nexthop: Nexthop information
    1463             :  * @param nlmsg: nlmsghdr structure to fill in.
    1464             :  * @param req_size: The size allocated for the message.
    1465             :  *
    1466             :  * The function returns true if the nexthop could be added
    1467             :  * to the message, otherwise false is returned.
    1468             :  */
    1469           0 : static bool _netlink_route_build_singlepath(const struct prefix *p,
    1470             :                                             const char *routedesc, int bytelen,
    1471             :                                             const struct nexthop *nexthop,
    1472             :                                             struct nlmsghdr *nlmsg,
    1473             :                                             struct rtmsg *rtmsg,
    1474             :                                             size_t req_size, int cmd)
    1475             : {
    1476             : 
    1477           0 :         char label_buf[256];
    1478           0 :         struct vrf *vrf;
    1479           0 :         char addrstr[INET6_ADDRSTRLEN];
    1480             : 
    1481           0 :         assert(nexthop);
    1482             : 
    1483           0 :         vrf = vrf_lookup_by_id(nexthop->vrf_id);
    1484             : 
    1485           0 :         if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
    1486             :                                               req_size, rtmsg, label_buf,
    1487             :                                               sizeof(label_buf)))
    1488             :                 return false;
    1489             : 
    1490           0 :         if (nexthop->nh_srv6) {
    1491           0 :                 if (nexthop->nh_srv6->seg6local_action !=
    1492             :                     ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
    1493           0 :                         struct rtattr *nest;
    1494           0 :                         const struct seg6local_context *ctx;
    1495             : 
    1496           0 :                         ctx = &nexthop->nh_srv6->seg6local_ctx;
    1497           0 :                         if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE,
    1498             :                                            LWTUNNEL_ENCAP_SEG6_LOCAL))
    1499             :                                 return false;
    1500             : 
    1501           0 :                         nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
    1502           0 :                         if (!nest)
    1503             :                                 return false;
    1504             : 
    1505           0 :                         switch (nexthop->nh_srv6->seg6local_action) {
    1506           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END:
    1507           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1508             :                                                    SEG6_LOCAL_ACTION,
    1509             :                                                    SEG6_LOCAL_ACTION_END))
    1510             :                                         return false;
    1511             :                                 break;
    1512           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_X:
    1513           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1514             :                                                    SEG6_LOCAL_ACTION,
    1515             :                                                    SEG6_LOCAL_ACTION_END_X))
    1516             :                                         return false;
    1517           0 :                                 if (!nl_attr_put(nlmsg, req_size,
    1518           0 :                                                  SEG6_LOCAL_NH6, &ctx->nh6,
    1519             :                                                  sizeof(struct in6_addr)))
    1520             :                                         return false;
    1521             :                                 break;
    1522           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_T:
    1523           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1524             :                                                    SEG6_LOCAL_ACTION,
    1525             :                                                    SEG6_LOCAL_ACTION_END_T))
    1526             :                                         return false;
    1527           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1528             :                                                    SEG6_LOCAL_TABLE,
    1529           0 :                                                    ctx->table))
    1530             :                                         return false;
    1531             :                                 break;
    1532           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
    1533           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1534             :                                                    SEG6_LOCAL_ACTION,
    1535             :                                                    SEG6_LOCAL_ACTION_END_DX4))
    1536             :                                         return false;
    1537           0 :                                 if (!nl_attr_put(nlmsg, req_size,
    1538           0 :                                                  SEG6_LOCAL_NH4, &ctx->nh4,
    1539             :                                                  sizeof(struct in_addr)))
    1540             :                                         return false;
    1541             :                                 break;
    1542           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
    1543           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1544             :                                                    SEG6_LOCAL_ACTION,
    1545             :                                                    SEG6_LOCAL_ACTION_END_DT6))
    1546             :                                         return false;
    1547           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1548             :                                                    SEG6_LOCAL_TABLE,
    1549           0 :                                                    ctx->table))
    1550             :                                         return false;
    1551             :                                 break;
    1552           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
    1553           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1554             :                                                    SEG6_LOCAL_ACTION,
    1555             :                                                    SEG6_LOCAL_ACTION_END_DT4))
    1556             :                                         return false;
    1557           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1558             :                                                    SEG6_LOCAL_VRFTABLE,
    1559           0 :                                                    ctx->table))
    1560             :                                         return false;
    1561             :                                 break;
    1562           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
    1563           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1564             :                                                    SEG6_LOCAL_ACTION,
    1565             :                                                    SEG6_LOCAL_ACTION_END_DT46))
    1566             :                                         return false;
    1567           0 :                                 if (!nl_attr_put32(nlmsg, req_size,
    1568             :                                                    SEG6_LOCAL_VRFTABLE,
    1569           0 :                                                    ctx->table))
    1570             :                                         return false;
    1571             :                                 break;
    1572           0 :                         case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
    1573             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
    1574             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
    1575             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
    1576             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
    1577             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_S:
    1578             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
    1579             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
    1580             :                         case ZEBRA_SEG6_LOCAL_ACTION_END_BPF:
    1581             :                         case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
    1582           0 :                                 zlog_err("%s: unsupport seg6local behaviour action=%u",
    1583             :                                          __func__,
    1584             :                                          nexthop->nh_srv6->seg6local_action);
    1585           0 :                                 return false;
    1586             :                         }
    1587           0 :                         nl_attr_nest_end(nlmsg, nest);
    1588             :                 }
    1589             : 
    1590           0 :                 if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) {
    1591           0 :                         char tun_buf[4096];
    1592           0 :                         ssize_t tun_len;
    1593           0 :                         struct rtattr *nest;
    1594             : 
    1595           0 :                         if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE,
    1596             :                                           LWTUNNEL_ENCAP_SEG6))
    1597           0 :                                 return false;
    1598           0 :                         nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
    1599           0 :                         if (!nest)
    1600             :                                 return false;
    1601           0 :                         tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf),
    1602           0 :                                         &nexthop->nh_srv6->seg6_segs);
    1603           0 :                         if (tun_len < 0)
    1604             :                                 return false;
    1605           0 :                         if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH,
    1606             :                                          tun_buf, tun_len))
    1607             :                                 return false;
    1608           0 :                         nl_attr_nest_end(nlmsg, nest);
    1609             :                 }
    1610             :         }
    1611             : 
    1612           0 :         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
    1613           0 :                 rtmsg->rtm_flags |= RTNH_F_ONLINK;
    1614             : 
    1615           0 :         if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
    1616           0 :                 rtmsg->rtm_flags |= RTNH_F_ONLINK;
    1617           0 :                 if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4))
    1618             :                         return false;
    1619           0 :                 if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
    1620             :                         return false;
    1621             : 
    1622           0 :                 if (cmd == RTM_NEWROUTE) {
    1623           0 :                         if (!_netlink_route_encode_nexthop_src(
    1624             :                                     nexthop, AF_INET, nlmsg, req_size, bytelen))
    1625             :                                 return false;
    1626             :                 }
    1627             : 
    1628           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    1629           0 :                         zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
    1630             :                                    __func__, routedesc, p, ipv4_ll_buf,
    1631             :                                    label_buf, nexthop->ifindex,
    1632             :                                    VRF_LOGNAME(vrf), nexthop->vrf_id);
    1633           0 :                 return true;
    1634             :         }
    1635             : 
    1636           0 :         if (nexthop->type == NEXTHOP_TYPE_IPV4
    1637           0 :             || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
    1638             :                 /* Send deletes to the kernel without specifying the next-hop */
    1639           0 :                 if (cmd != RTM_DELROUTE) {
    1640           0 :                         if (!_netlink_route_add_gateway_info(
    1641             :                                     rtmsg->rtm_family, AF_INET, nlmsg, req_size,
    1642             :                                     bytelen, nexthop))
    1643             :                                 return false;
    1644             :                 }
    1645             : 
    1646           0 :                 if (cmd == RTM_NEWROUTE) {
    1647           0 :                         if (!_netlink_route_encode_nexthop_src(
    1648             :                                     nexthop, AF_INET, nlmsg, req_size, bytelen))
    1649             :                                 return false;
    1650             :                 }
    1651             : 
    1652           0 :                 if (IS_ZEBRA_DEBUG_KERNEL) {
    1653           0 :                         inet_ntop(AF_INET, &nexthop->gate.ipv4, addrstr,
    1654             :                                   sizeof(addrstr));
    1655           0 :                         zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
    1656             :                                    __func__, routedesc, p, addrstr, label_buf,
    1657             :                                    nexthop->ifindex, VRF_LOGNAME(vrf),
    1658             :                                    nexthop->vrf_id);
    1659             :                 }
    1660             :         }
    1661             : 
    1662           0 :         if (nexthop->type == NEXTHOP_TYPE_IPV6
    1663           0 :             || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
    1664           0 :                 if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
    1665             :                                                      AF_INET6, nlmsg, req_size,
    1666             :                                                      bytelen, nexthop))
    1667             :                         return false;
    1668             : 
    1669           0 :                 if (cmd == RTM_NEWROUTE) {
    1670           0 :                         if (!_netlink_route_encode_nexthop_src(
    1671             :                                     nexthop, AF_INET6, nlmsg, req_size,
    1672             :                                     bytelen))
    1673             :                                 return false;
    1674             :                 }
    1675             : 
    1676           0 :                 if (IS_ZEBRA_DEBUG_KERNEL) {
    1677           0 :                         inet_ntop(AF_INET6, &nexthop->gate.ipv6, addrstr,
    1678             :                                   sizeof(addrstr));
    1679           0 :                         zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
    1680             :                                    __func__, routedesc, p, addrstr, label_buf,
    1681             :                                    nexthop->ifindex, VRF_LOGNAME(vrf),
    1682             :                                    nexthop->vrf_id);
    1683             :                 }
    1684             :         }
    1685             : 
    1686             :         /*
    1687             :          * We have the ifindex so we should always send it
    1688             :          * This is especially useful if we are doing route
    1689             :          * leaking.
    1690             :          */
    1691           0 :         if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
    1692           0 :                 if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
    1693             :                         return false;
    1694             :         }
    1695             : 
    1696           0 :         if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
    1697           0 :                 if (cmd == RTM_NEWROUTE) {
    1698           0 :                         if (!_netlink_route_encode_nexthop_src(
    1699             :                                     nexthop, AF_INET, nlmsg, req_size, bytelen))
    1700             :                                 return false;
    1701             :                 }
    1702             : 
    1703           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    1704           0 :                         zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
    1705             :                                    __func__, routedesc, p, nexthop->ifindex,
    1706             :                                    VRF_LOGNAME(vrf), nexthop->vrf_id);
    1707             :         }
    1708             : 
    1709             :         return true;
    1710             : }
    1711             : 
    1712             : /* This function appends tag value as rtnl flow attribute
    1713             :  * to the given netlink msg only if value is less than 256.
    1714             :  * Used only if SUPPORT_REALMS enabled.
    1715             :  *
    1716             :  * @param nlmsg: nlmsghdr structure to fill in.
    1717             :  * @param maxlen: The size allocated for the message.
    1718             :  * @param tag: The route tag.
    1719             :  *
    1720             :  * The function returns true if the flow attribute could
    1721             :  * be added to the message, otherwise false is returned.
    1722             :  */
    1723           3 : static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen,
    1724             :                                     route_tag_t tag)
    1725             : {
    1726           3 :         if (tag > 0 && tag <= 255) {
    1727           0 :                 if (!nl_attr_put32(n, maxlen, RTA_FLOW, tag))
    1728             :                         return false;
    1729             :         }
    1730             :         return true;
    1731             : }
    1732             : 
    1733             : /* This function takes a nexthop as argument and
    1734             :  * appends to the given netlink msg. If the nexthop
    1735             :  * defines a preferred source, the src parameter
    1736             :  * will be modified to point to that src, otherwise
    1737             :  * it will be kept unmodified.
    1738             :  *
    1739             :  * @param routedesc: Human readable description of route type
    1740             :  *                   (direct/recursive, single-/multipath)
    1741             :  * @param bytelen: Length of addresses in bytes.
    1742             :  * @param nexthop: Nexthop information
    1743             :  * @param nlmsg: nlmsghdr structure to fill in.
    1744             :  * @param req_size: The size allocated for the message.
    1745             :  * @param src: pointer pointing to a location where
    1746             :  *             the prefsrc should be stored.
    1747             :  *
    1748             :  * The function returns true if the nexthop could be added
    1749             :  * to the message, otherwise false is returned.
    1750             :  */
    1751           0 : static bool _netlink_route_build_multipath(
    1752             :         const struct prefix *p, const char *routedesc, int bytelen,
    1753             :         const struct nexthop *nexthop, struct nlmsghdr *nlmsg, size_t req_size,
    1754             :         struct rtmsg *rtmsg, const union g_addr **src, route_tag_t tag)
    1755             : {
    1756           0 :         char label_buf[256];
    1757           0 :         struct vrf *vrf;
    1758           0 :         struct rtnexthop *rtnh;
    1759             : 
    1760           0 :         rtnh = nl_attr_rtnh(nlmsg, req_size);
    1761           0 :         if (rtnh == NULL)
    1762             :                 return false;
    1763             : 
    1764           0 :         assert(nexthop);
    1765             : 
    1766           0 :         vrf = vrf_lookup_by_id(nexthop->vrf_id);
    1767             : 
    1768           0 :         if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
    1769             :                                               req_size, rtmsg, label_buf,
    1770             :                                               sizeof(label_buf)))
    1771             :                 return false;
    1772             : 
    1773           0 :         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
    1774           0 :                 rtnh->rtnh_flags |= RTNH_F_ONLINK;
    1775             : 
    1776           0 :         if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
    1777           0 :                 rtnh->rtnh_flags |= RTNH_F_ONLINK;
    1778           0 :                 if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4))
    1779             :                         return false;
    1780           0 :                 rtnh->rtnh_ifindex = nexthop->ifindex;
    1781           0 :                 if (nexthop->weight)
    1782           0 :                         rtnh->rtnh_hops = nexthop->weight - 1;
    1783             : 
    1784           0 :                 if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
    1785           0 :                         *src = &nexthop->rmap_src;
    1786           0 :                 else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
    1787           0 :                         *src = &nexthop->src;
    1788             : 
    1789           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    1790           0 :                         zlog_debug(
    1791             :                                 "%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
    1792             :                                 __func__, routedesc, p, ipv4_ll_buf, label_buf,
    1793             :                                 nexthop->ifindex, VRF_LOGNAME(vrf),
    1794             :                                 nexthop->vrf_id);
    1795           0 :                 nl_attr_rtnh_end(nlmsg, rtnh);
    1796           0 :                 return true;
    1797             :         }
    1798             : 
    1799           0 :         if (nexthop->type == NEXTHOP_TYPE_IPV4
    1800           0 :             || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
    1801           0 :                 if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET,
    1802             :                                                      nlmsg, req_size, bytelen,
    1803             :                                                      nexthop))
    1804             :                         return false;
    1805             : 
    1806           0 :                 if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
    1807           0 :                         *src = &nexthop->rmap_src;
    1808           0 :                 else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
    1809           0 :                         *src = &nexthop->src;
    1810             : 
    1811           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    1812           0 :                         zlog_debug("%s: (%s): %pFX nexthop via %pI4 %s if %u vrf %s(%u)",
    1813             :                                    __func__, routedesc, p, &nexthop->gate.ipv4,
    1814             :                                    label_buf, nexthop->ifindex,
    1815             :                                    VRF_LOGNAME(vrf), nexthop->vrf_id);
    1816             :         }
    1817           0 :         if (nexthop->type == NEXTHOP_TYPE_IPV6
    1818           0 :             || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
    1819           0 :                 if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
    1820             :                                                      AF_INET6, nlmsg, req_size,
    1821             :                                                      bytelen, nexthop))
    1822             :                         return false;
    1823             : 
    1824           0 :                 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
    1825           0 :                         *src = &nexthop->rmap_src;
    1826           0 :                 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
    1827           0 :                         *src = &nexthop->src;
    1828             : 
    1829           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    1830           0 :                         zlog_debug("%s: (%s): %pFX nexthop via %pI6 %s if %u vrf %s(%u)",
    1831             :                                    __func__, routedesc, p, &nexthop->gate.ipv6,
    1832             :                                    label_buf, nexthop->ifindex,
    1833             :                                    VRF_LOGNAME(vrf), nexthop->vrf_id);
    1834             :         }
    1835             : 
    1836             :         /*
    1837             :          * We have figured out the ifindex so we should always send it
    1838             :          * This is especially useful if we are doing route
    1839             :          * leaking.
    1840             :          */
    1841           0 :         if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
    1842           0 :                 rtnh->rtnh_ifindex = nexthop->ifindex;
    1843             : 
    1844             :         /* ifindex */
    1845           0 :         if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
    1846           0 :                 if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
    1847           0 :                         *src = &nexthop->rmap_src;
    1848           0 :                 else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
    1849           0 :                         *src = &nexthop->src;
    1850             : 
    1851           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    1852           0 :                         zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
    1853             :                                    __func__, routedesc, p, nexthop->ifindex,
    1854             :                                    VRF_LOGNAME(vrf), nexthop->vrf_id);
    1855             :         }
    1856             : 
    1857           0 :         if (nexthop->weight)
    1858           0 :                 rtnh->rtnh_hops = nexthop->weight - 1;
    1859             : 
    1860           0 :         if (!_netlink_set_tag(nlmsg, req_size, tag))
    1861             :                 return false;
    1862             : 
    1863           0 :         nl_attr_rtnh_end(nlmsg, rtnh);
    1864           0 :         return true;
    1865             : }
    1866             : 
    1867             : static inline bool
    1868           0 : _netlink_mpls_build_singlepath(const struct prefix *p, const char *routedesc,
    1869             :                                const struct zebra_nhlfe *nhlfe,
    1870             :                                struct nlmsghdr *nlmsg, struct rtmsg *rtmsg,
    1871             :                                size_t req_size, int cmd)
    1872             : {
    1873           0 :         int bytelen;
    1874           0 :         uint8_t family;
    1875             : 
    1876           0 :         family = NHLFE_FAMILY(nhlfe);
    1877           0 :         bytelen = (family == AF_INET ? 4 : 16);
    1878           0 :         return _netlink_route_build_singlepath(p, routedesc, bytelen,
    1879             :                                                nhlfe->nexthop, nlmsg, rtmsg,
    1880             :                                                req_size, cmd);
    1881             : }
    1882             : 
    1883             : 
    1884             : static inline bool
    1885           0 : _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
    1886             :                               const struct zebra_nhlfe *nhlfe,
    1887             :                               struct nlmsghdr *nlmsg, size_t req_size,
    1888             :                               struct rtmsg *rtmsg, const union g_addr **src)
    1889             : {
    1890           0 :         int bytelen;
    1891           0 :         uint8_t family;
    1892             : 
    1893           0 :         family = NHLFE_FAMILY(nhlfe);
    1894           0 :         bytelen = (family == AF_INET ? 4 : 16);
    1895           0 :         return _netlink_route_build_multipath(p, routedesc, bytelen,
    1896             :                                               nhlfe->nexthop, nlmsg, req_size,
    1897             :                                               rtmsg, src, 0);
    1898             : }
    1899             : 
    1900           0 : static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
    1901             : {
    1902           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    1903           0 :                 zlog_debug("netlink_mpls_multipath_msg_encode() (%s): %s %u/20",
    1904             :                            routedesc, nl_msg_type_to_str(cmd), label);
    1905           0 : }
    1906             : 
    1907           0 : static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla,
    1908             :                                 int llalen, ns_id_t ns_id, uint8_t family,
    1909             :                                 bool permanent, uint8_t protocol)
    1910             : {
    1911           0 :         struct {
    1912             :                 struct nlmsghdr n;
    1913             :                 struct ndmsg ndm;
    1914             :                 char buf[256];
    1915             :         } req;
    1916             : 
    1917           0 :         struct zebra_ns *zns = zebra_ns_lookup(ns_id);
    1918             : 
    1919           0 :         memset(&req, 0, sizeof(req));
    1920             : 
    1921           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
    1922           0 :         req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
    1923           0 :         req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH
    1924           0 :         req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
    1925             : 
    1926           0 :         req.ndm.ndm_family = family;
    1927           0 :         req.ndm.ndm_ifindex = ifindex;
    1928           0 :         req.ndm.ndm_type = RTN_UNICAST;
    1929           0 :         if (cmd == RTM_NEWNEIGH) {
    1930           0 :                 if (!permanent)
    1931           0 :                         req.ndm.ndm_state = NUD_REACHABLE;
    1932             :                 else
    1933           0 :                         req.ndm.ndm_state = NUD_PERMANENT;
    1934             :         } else
    1935           0 :                 req.ndm.ndm_state = NUD_FAILED;
    1936             : 
    1937           0 :         nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol,
    1938             :                     sizeof(protocol));
    1939           0 :         req.ndm.ndm_type = RTN_UNICAST;
    1940           0 :         nl_attr_put(&req.n, sizeof(req), NDA_DST, addr,
    1941           0 :                     family2addrsize(family));
    1942           0 :         if (lla)
    1943           0 :                 nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
    1944             : 
    1945           0 :         return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
    1946             :                             false);
    1947             : }
    1948             : 
    1949           4 : static bool nexthop_set_src(const struct nexthop *nexthop, int family,
    1950             :                             union g_addr *src)
    1951             : {
    1952           4 :         if (family == AF_INET) {
    1953           4 :                 if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
    1954           0 :                         src->ipv4 = nexthop->rmap_src.ipv4;
    1955           0 :                         return true;
    1956           4 :                 } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
    1957           0 :                         src->ipv4 = nexthop->src.ipv4;
    1958           0 :                         return true;
    1959             :                 }
    1960           0 :         } else if (family == AF_INET6) {
    1961           0 :                 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
    1962           0 :                         src->ipv6 = nexthop->rmap_src.ipv6;
    1963           0 :                         return true;
    1964           0 :                 } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) {
    1965           0 :                         src->ipv6 = nexthop->src.ipv6;
    1966           0 :                         return true;
    1967             :                 }
    1968             :         }
    1969             : 
    1970             :         return false;
    1971             : }
    1972             : 
    1973             : /*
    1974             :  * The function returns true if the attribute could be added
    1975             :  * to the message, otherwise false is returned.
    1976             :  */
    1977           0 : static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
    1978             :                                        struct nexthop *nh)
    1979             : {
    1980           0 :         struct rtattr *nest;
    1981             : 
    1982           0 :         switch (nh->nh_encap_type) {
    1983           0 :         case NET_VXLAN:
    1984           0 :                 if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type))
    1985             :                         return false;
    1986             : 
    1987           0 :                 nest = nl_attr_nest(n, nlen, RTA_ENCAP);
    1988           0 :                 if (!nest)
    1989             :                         return false;
    1990             : 
    1991           0 :                 if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */,
    1992             :                                    nh->nh_encap.vni))
    1993             :                         return false;
    1994           0 :                 nl_attr_nest_end(n, nest);
    1995           0 :                 break;
    1996             :         }
    1997             : 
    1998             :         return true;
    1999             : }
    2000             : 
    2001             : /*
    2002             :  * Routing table change via netlink interface, using a dataplane context object
    2003             :  *
    2004             :  * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
    2005             :  * otherwise the number of bytes written to buf.
    2006             :  */
    2007           7 : ssize_t netlink_route_multipath_msg_encode(int cmd,
    2008             :                                            struct zebra_dplane_ctx *ctx,
    2009             :                                            uint8_t *data, size_t datalen,
    2010             :                                            bool fpm, bool force_nhg)
    2011             : {
    2012           7 :         int bytelen;
    2013           7 :         struct nexthop *nexthop = NULL;
    2014           7 :         unsigned int nexthop_num;
    2015           7 :         const char *routedesc;
    2016           7 :         bool setsrc = false;
    2017           7 :         union g_addr src;
    2018           7 :         const struct prefix *p, *src_p;
    2019           7 :         uint32_t table_id;
    2020           7 :         struct nlsock *nl;
    2021           7 :         route_tag_t tag = 0;
    2022             : 
    2023           7 :         struct {
    2024             :                 struct nlmsghdr n;
    2025             :                 struct rtmsg r;
    2026             :                 char buf[];
    2027           7 :         } *req = (void *)data;
    2028             : 
    2029           7 :         p = dplane_ctx_get_dest(ctx);
    2030           7 :         src_p = dplane_ctx_get_src(ctx);
    2031             : 
    2032           7 :         if (datalen < sizeof(*req))
    2033             :                 return 0;
    2034             : 
    2035           7 :         nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
    2036             : 
    2037           7 :         memset(req, 0, sizeof(*req));
    2038             : 
    2039           7 :         bytelen = (p->family == AF_INET ? 4 : 16);
    2040             : 
    2041           7 :         req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    2042           7 :         req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
    2043             : 
    2044           7 :         if ((cmd == RTM_NEWROUTE) &&
    2045           0 :             ((p->family == AF_INET) || v6_rr_semantics))
    2046           4 :                 req->n.nlmsg_flags |= NLM_F_REPLACE;
    2047             : 
    2048           7 :         req->n.nlmsg_type = cmd;
    2049             : 
    2050           7 :         req->n.nlmsg_pid = nl->snl.nl_pid;
    2051             : 
    2052           7 :         req->r.rtm_family = p->family;
    2053           7 :         req->r.rtm_dst_len = p->prefixlen;
    2054           7 :         req->r.rtm_src_len = src_p ? src_p->prefixlen : 0;
    2055           7 :         req->r.rtm_scope = RT_SCOPE_UNIVERSE;
    2056             : 
    2057           7 :         if (cmd == RTM_DELROUTE)
    2058           3 :                 req->r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx));
    2059             :         else
    2060           4 :                 req->r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx));
    2061             : 
    2062             :         /*
    2063             :          * blackhole routes are not RTN_UNICAST, they are
    2064             :          * RTN_ BLACKHOLE|UNREACHABLE|PROHIBIT
    2065             :          * so setting this value as a RTN_UNICAST would
    2066             :          * cause the route lookup of just the prefix
    2067             :          * to fail.  So no need to specify this for
    2068             :          * the RTM_DELROUTE case
    2069             :          */
    2070           7 :         if (cmd != RTM_DELROUTE)
    2071           4 :                 req->r.rtm_type = RTN_UNICAST;
    2072             : 
    2073           7 :         if (!nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen))
    2074             :                 return 0;
    2075           7 :         if (src_p) {
    2076           0 :                 if (!nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix,
    2077             :                                  bytelen))
    2078             :                         return 0;
    2079             :         }
    2080             : 
    2081             :         /* Metric. */
    2082             :         /* Hardcode the metric for all routes coming from zebra. Metric isn't
    2083             :          * used
    2084             :          * either by the kernel or by zebra. Its purely for calculating best
    2085             :          * path(s)
    2086             :          * by the routing protocol and for communicating with protocol peers.
    2087             :          */
    2088           7 :         if (!nl_attr_put32(&req->n, datalen, RTA_PRIORITY,
    2089             :                            ROUTE_INSTALLATION_METRIC))
    2090             :                 return 0;
    2091             : 
    2092             : #if defined(SUPPORT_REALMS)
    2093             :         if (cmd == RTM_DELROUTE)
    2094             :                 tag = dplane_ctx_get_old_tag(ctx);
    2095             :         else
    2096             :                 tag = dplane_ctx_get_tag(ctx);
    2097             : #endif
    2098             : 
    2099             :         /* Table corresponding to this route. */
    2100           7 :         table_id = dplane_ctx_get_table(ctx);
    2101           7 :         if (table_id < 256)
    2102           7 :                 req->r.rtm_table = table_id;
    2103             :         else {
    2104           0 :                 req->r.rtm_table = RT_TABLE_UNSPEC;
    2105           0 :                 if (!nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id))
    2106             :                         return 0;
    2107             :         }
    2108             : 
    2109           7 :         if (IS_ZEBRA_DEBUG_KERNEL)
    2110           0 :                 zlog_debug(
    2111             :                         "%s: %s %pFX vrf %u(%u)", __func__,
    2112             :                         nl_msg_type_to_str(cmd), p, dplane_ctx_get_vrf(ctx),
    2113             :                         table_id);
    2114             : 
    2115             :         /*
    2116             :          * If we are not updating the route and we have received
    2117             :          * a route delete, then all we need to fill in is the
    2118             :          * prefix information to tell the kernel to schwack
    2119             :          * it.
    2120             :          */
    2121           7 :         if (cmd == RTM_DELROUTE) {
    2122           3 :                 if (!_netlink_set_tag(&req->n, datalen, tag))
    2123             :                         return 0;
    2124           3 :                 return NLMSG_ALIGN(req->n.nlmsg_len);
    2125             :         }
    2126             : 
    2127           4 :         if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) {
    2128           0 :                 struct rtattr *nest;
    2129           0 :                 uint32_t mtu = dplane_ctx_get_mtu(ctx);
    2130           0 :                 uint32_t nexthop_mtu = dplane_ctx_get_nh_mtu(ctx);
    2131             : 
    2132           0 :                 if (!mtu || (nexthop_mtu && nexthop_mtu < mtu))
    2133           0 :                         mtu = nexthop_mtu;
    2134             : 
    2135           0 :                 nest = nl_attr_nest(&req->n, datalen, RTA_METRICS);
    2136           0 :                 if (nest == NULL)
    2137           0 :                         return 0;
    2138             : 
    2139           0 :                 if (!nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu)))
    2140             :                         return 0;
    2141           0 :                 nl_attr_nest_end(&req->n, nest);
    2142             :         }
    2143             : 
    2144             :         /*
    2145             :          * Always install blackhole routes without using nexthops, because of
    2146             :          * the following kernel problems:
    2147             :          * 1. Kernel nexthops don't suport unreachable/prohibit route types.
    2148             :          * 2. Blackhole kernel nexthops are deleted when loopback is down.
    2149             :          */
    2150           4 :         nexthop = dplane_ctx_get_ng(ctx)->nexthop;
    2151           4 :         if (nexthop) {
    2152           4 :                 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
    2153           0 :                         nexthop = nexthop->resolved;
    2154             : 
    2155           4 :                 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
    2156           0 :                         switch (nexthop->bh_type) {
    2157           0 :                         case BLACKHOLE_ADMINPROHIB:
    2158           0 :                                 req->r.rtm_type = RTN_PROHIBIT;
    2159           0 :                                 break;
    2160           0 :                         case BLACKHOLE_REJECT:
    2161           0 :                                 req->r.rtm_type = RTN_UNREACHABLE;
    2162           0 :                                 break;
    2163           0 :                         case BLACKHOLE_UNSPEC:
    2164             :                         case BLACKHOLE_NULL:
    2165           0 :                                 req->r.rtm_type = RTN_BLACKHOLE;
    2166           0 :                                 break;
    2167             :                         }
    2168           0 :                         return NLMSG_ALIGN(req->n.nlmsg_len);
    2169             :                 }
    2170             :         }
    2171             : 
    2172           4 :         if ((!fpm && kernel_nexthops_supported()
    2173           4 :              && (!proto_nexthops_only()
    2174           0 :                  || is_proto_nhg(dplane_ctx_get_nhe_id(ctx), 0)))
    2175           0 :             || (fpm && force_nhg)) {
    2176             :                 /* Kernel supports nexthop objects */
    2177           4 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    2178           0 :                         zlog_debug("%s: %pFX nhg_id is %u", __func__, p,
    2179             :                                    dplane_ctx_get_nhe_id(ctx));
    2180             : 
    2181           4 :                 if (!nl_attr_put32(&req->n, datalen, RTA_NH_ID,
    2182             :                                    dplane_ctx_get_nhe_id(ctx)))
    2183             :                         return 0;
    2184             : 
    2185             :                 /* Have to determine src still */
    2186           8 :                 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
    2187           4 :                         if (setsrc)
    2188             :                                 break;
    2189             : 
    2190           4 :                         setsrc = nexthop_set_src(nexthop, p->family, &src);
    2191             :                 }
    2192             : 
    2193           4 :                 if (setsrc) {
    2194           0 :                         if (p->family == AF_INET) {
    2195           0 :                                 if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
    2196             :                                                  &src.ipv4, bytelen))
    2197             :                                         return 0;
    2198           0 :                         } else if (p->family == AF_INET6) {
    2199           0 :                                 if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
    2200             :                                                  &src.ipv6, bytelen))
    2201             :                                         return 0;
    2202             :                         }
    2203             :                 }
    2204             : 
    2205           4 :                 return NLMSG_ALIGN(req->n.nlmsg_len);
    2206             :         }
    2207             : 
    2208             :         /* Count overall nexthops so we can decide whether to use singlepath
    2209             :          * or multipath case.
    2210             :          */
    2211           0 :         nexthop_num = 0;
    2212           0 :         for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
    2213           0 :                 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
    2214           0 :                         continue;
    2215           0 :                 if (!NEXTHOP_IS_ACTIVE(nexthop->flags))
    2216           0 :                         continue;
    2217             : 
    2218           0 :                 nexthop_num++;
    2219             :         }
    2220             : 
    2221             :         /* Singlepath case. */
    2222           0 :         if (nexthop_num == 1) {
    2223           0 :                 nexthop_num = 0;
    2224           0 :                 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
    2225           0 :                         if (CHECK_FLAG(nexthop->flags,
    2226             :                                        NEXTHOP_FLAG_RECURSIVE)) {
    2227             : 
    2228           0 :                                 if (setsrc)
    2229           0 :                                         continue;
    2230             : 
    2231           0 :                                 setsrc = nexthop_set_src(nexthop, p->family,
    2232             :                                                          &src);
    2233           0 :                                 continue;
    2234             :                         }
    2235             : 
    2236           0 :                         if (NEXTHOP_IS_ACTIVE(nexthop->flags)) {
    2237           0 :                                 routedesc = nexthop->rparent
    2238             :                                                     ? "recursive, single-path"
    2239           0 :                                                     : "single-path";
    2240             : 
    2241           0 :                                 if (!_netlink_set_tag(&req->n, datalen, tag))
    2242             :                                         return 0;
    2243             : 
    2244           0 :                                 if (!_netlink_route_build_singlepath(
    2245             :                                             p, routedesc, bytelen, nexthop,
    2246             :                                             &req->n, &req->r, datalen, cmd))
    2247             :                                         return 0;
    2248             :                                 nexthop_num++;
    2249             :                                 break;
    2250             :                         }
    2251             : 
    2252             :                         /*
    2253             :                          * Add encapsulation information when installing via
    2254             :                          * FPM.
    2255             :                          */
    2256           0 :                         if (fpm) {
    2257           0 :                                 if (!netlink_route_nexthop_encap(
    2258             :                                             &req->n, datalen, nexthop))
    2259             :                                         return 0;
    2260             :                         }
    2261             :                 }
    2262             : 
    2263           0 :                 if (setsrc) {
    2264           0 :                         if (p->family == AF_INET) {
    2265           0 :                                 if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
    2266             :                                                  &src.ipv4, bytelen))
    2267             :                                         return 0;
    2268           0 :                         } else if (p->family == AF_INET6) {
    2269           0 :                                 if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
    2270             :                                                  &src.ipv6, bytelen))
    2271             :                                         return 0;
    2272             :                         }
    2273             :                 }
    2274             :         } else {    /* Multipath case */
    2275           0 :                 struct rtattr *nest;
    2276           0 :                 const union g_addr *src1 = NULL;
    2277             : 
    2278           0 :                 nest = nl_attr_nest(&req->n, datalen, RTA_MULTIPATH);
    2279           0 :                 if (nest == NULL)
    2280           0 :                         return 0;
    2281             : 
    2282           0 :                 nexthop_num = 0;
    2283           0 :                 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
    2284           0 :                         if (CHECK_FLAG(nexthop->flags,
    2285             :                                        NEXTHOP_FLAG_RECURSIVE)) {
    2286             :                                 /* This only works for IPv4 now */
    2287           0 :                                 if (setsrc)
    2288           0 :                                         continue;
    2289             : 
    2290           0 :                                 setsrc = nexthop_set_src(nexthop, p->family,
    2291             :                                                          &src);
    2292           0 :                                 continue;
    2293             :                         }
    2294             : 
    2295           0 :                         if (NEXTHOP_IS_ACTIVE(nexthop->flags)) {
    2296           0 :                                 routedesc = nexthop->rparent
    2297             :                                                     ? "recursive, multipath"
    2298           0 :                                                     : "multipath";
    2299           0 :                                 nexthop_num++;
    2300             : 
    2301           0 :                                 if (!_netlink_route_build_multipath(
    2302             :                                             p, routedesc, bytelen, nexthop,
    2303             :                                             &req->n, datalen, &req->r, &src1,
    2304             :                                             tag))
    2305             :                                         return 0;
    2306             : 
    2307           0 :                                 if (!setsrc && src1) {
    2308           0 :                                         if (p->family == AF_INET)
    2309           0 :                                                 src.ipv4 = src1->ipv4;
    2310           0 :                                         else if (p->family == AF_INET6)
    2311           0 :                                                 src.ipv6 = src1->ipv6;
    2312             : 
    2313             :                                         setsrc = 1;
    2314             :                                 }
    2315             :                         }
    2316             :                 }
    2317             : 
    2318           0 :                 nl_attr_nest_end(&req->n, nest);
    2319             : 
    2320             :                 /*
    2321             :                  * Add encapsulation information when installing via
    2322             :                  * FPM.
    2323             :                  */
    2324           0 :                 if (fpm) {
    2325           0 :                         for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
    2326             :                                               nexthop)) {
    2327           0 :                                 if (CHECK_FLAG(nexthop->flags,
    2328             :                                                NEXTHOP_FLAG_RECURSIVE))
    2329           0 :                                         continue;
    2330           0 :                                 if (!netlink_route_nexthop_encap(
    2331             :                                             &req->n, datalen, nexthop))
    2332             :                                         return 0;
    2333             :                         }
    2334             :                 }
    2335             : 
    2336             : 
    2337           0 :                 if (setsrc) {
    2338           0 :                         if (p->family == AF_INET) {
    2339           0 :                                 if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
    2340             :                                                  &src.ipv4, bytelen))
    2341             :                                         return 0;
    2342           0 :                         } else if (p->family == AF_INET6) {
    2343           0 :                                 if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
    2344             :                                                  &src.ipv6, bytelen))
    2345             :                                         return 0;
    2346             :                         }
    2347           0 :                         if (IS_ZEBRA_DEBUG_KERNEL)
    2348           0 :                                 zlog_debug("Setting source");
    2349             :                 }
    2350             :         }
    2351             : 
    2352             :         /* If there is no useful nexthop then return. */
    2353           0 :         if (nexthop_num == 0) {
    2354           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    2355           0 :                         zlog_debug("%s: No useful nexthop.", __func__);
    2356             :         }
    2357             : 
    2358           0 :         return NLMSG_ALIGN(req->n.nlmsg_len);
    2359             : }
    2360             : 
    2361           0 : int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
    2362             : {
    2363           0 :         uint32_t actual_table;
    2364           0 :         int suc = 0;
    2365           0 :         struct mcast_route_data *mr = (struct mcast_route_data *)in;
    2366           0 :         struct {
    2367             :                 struct nlmsghdr n;
    2368             :                 struct rtmsg rtm;
    2369             :                 char buf[256];
    2370             :         } req;
    2371             : 
    2372           0 :         mroute = mr;
    2373           0 :         struct zebra_ns *zns;
    2374             : 
    2375           0 :         zns = zvrf->zns;
    2376           0 :         memset(&req, 0, sizeof(req));
    2377             : 
    2378           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    2379           0 :         req.n.nlmsg_flags = NLM_F_REQUEST;
    2380           0 :         req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
    2381             : 
    2382           0 :         req.n.nlmsg_type = RTM_GETROUTE;
    2383             : 
    2384           0 :         if (mroute->family == AF_INET) {
    2385           0 :                 req.rtm.rtm_family = RTNL_FAMILY_IPMR;
    2386           0 :                 req.rtm.rtm_dst_len = IPV4_MAX_BITLEN;
    2387           0 :                 req.rtm.rtm_src_len = IPV4_MAX_BITLEN;
    2388             : 
    2389           0 :                 nl_attr_put(&req.n, sizeof(req), RTA_SRC,
    2390           0 :                             &mroute->src.ipaddr_v4,
    2391             :                             sizeof(mroute->src.ipaddr_v4));
    2392           0 :                 nl_attr_put(&req.n, sizeof(req), RTA_DST,
    2393           0 :                             &mroute->grp.ipaddr_v4,
    2394             :                             sizeof(mroute->grp.ipaddr_v4));
    2395             :         } else {
    2396           0 :                 req.rtm.rtm_family = RTNL_FAMILY_IP6MR;
    2397           0 :                 req.rtm.rtm_dst_len = IPV6_MAX_BITLEN;
    2398           0 :                 req.rtm.rtm_src_len = IPV6_MAX_BITLEN;
    2399             : 
    2400           0 :                 nl_attr_put(&req.n, sizeof(req), RTA_SRC,
    2401           0 :                             &mroute->src.ipaddr_v6,
    2402             :                             sizeof(mroute->src.ipaddr_v6));
    2403           0 :                 nl_attr_put(&req.n, sizeof(req), RTA_DST,
    2404           0 :                             &mroute->grp.ipaddr_v6,
    2405             :                             sizeof(mroute->grp.ipaddr_v6));
    2406             :         }
    2407             : 
    2408             :         /*
    2409             :          * What?
    2410             :          *
    2411             :          * So during the namespace cleanup we started storing
    2412             :          * the zvrf table_id for the default table as RT_TABLE_MAIN
    2413             :          * which is what the normal routing table for ip routing is.
    2414             :          * This change caused this to break our lookups of sg data
    2415             :          * because prior to this change the zvrf->table_id was 0
    2416             :          * and when the pim multicast kernel code saw a 0,
    2417             :          * it was auto-translated to RT_TABLE_DEFAULT.  But since
    2418             :          * we are now passing in RT_TABLE_MAIN there is no auto-translation
    2419             :          * and the kernel goes screw you and the delicious cookies you
    2420             :          * are trying to give me.  So now we have this little hack.
    2421             :          */
    2422           0 :         if (mroute->family == AF_INET)
    2423           0 :                 actual_table = (zvrf->table_id == RT_TABLE_MAIN)
    2424             :                                        ? RT_TABLE_DEFAULT
    2425           0 :                                        : zvrf->table_id;
    2426             :         else
    2427           0 :                 actual_table = zvrf->table_id;
    2428             : 
    2429           0 :         nl_attr_put32(&req.n, sizeof(req), RTA_TABLE, actual_table);
    2430             : 
    2431           0 :         suc = netlink_talk(netlink_route_change_read_multicast, &req.n,
    2432             :                            &zns->netlink_cmd, zns, false);
    2433             : 
    2434           0 :         mroute = NULL;
    2435           0 :         return suc;
    2436             : }
    2437             : 
    2438             : /* Char length to debug ID with */
    2439             : #define ID_LENGTH 10
    2440             : 
    2441           0 : static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
    2442             :                                          uint32_t id,
    2443             :                                          const struct nh_grp *z_grp,
    2444             :                                          const uint8_t count, bool resilient,
    2445             :                                          const struct nhg_resilience *nhgr)
    2446           0 : {
    2447           0 :         struct nexthop_grp grp[count];
    2448             :         /* Need space for max group size, "/", and null term */
    2449           0 :         char buf[(MULTIPATH_NUM * (ID_LENGTH + 1)) + 1];
    2450           0 :         char buf1[ID_LENGTH + 2];
    2451             : 
    2452           0 :         buf[0] = '\0';
    2453             : 
    2454           0 :         memset(grp, 0, sizeof(grp));
    2455             : 
    2456           0 :         if (count) {
    2457           0 :                 for (int i = 0; i < count; i++) {
    2458           0 :                         grp[i].id = z_grp[i].id;
    2459           0 :                         grp[i].weight = z_grp[i].weight - 1;
    2460             : 
    2461           0 :                         if (IS_ZEBRA_DEBUG_KERNEL) {
    2462           0 :                                 if (i == 0)
    2463           0 :                                         snprintf(buf, sizeof(buf1), "group %u",
    2464             :                                                  grp[i].id);
    2465             :                                 else {
    2466           0 :                                         snprintf(buf1, sizeof(buf1), "/%u",
    2467             :                                                  grp[i].id);
    2468           0 :                                         strlcat(buf, buf1, sizeof(buf));
    2469             :                                 }
    2470             :                         }
    2471             :                 }
    2472           0 :                 if (!nl_attr_put(n, req_size, NHA_GROUP, grp,
    2473             :                                  count * sizeof(*grp)))
    2474             :                         return false;
    2475             : 
    2476           0 :                 if (resilient) {
    2477           0 :                         struct rtattr *nest;
    2478             : 
    2479           0 :                         nest = nl_attr_nest(n, req_size, NHA_RES_GROUP);
    2480             : 
    2481           0 :                         nl_attr_put16(n, req_size, NHA_RES_GROUP_BUCKETS,
    2482           0 :                                       nhgr->buckets);
    2483           0 :                         nl_attr_put32(n, req_size, NHA_RES_GROUP_IDLE_TIMER,
    2484           0 :                                       nhgr->idle_timer * 1000);
    2485           0 :                         nl_attr_put32(n, req_size,
    2486             :                                       NHA_RES_GROUP_UNBALANCED_TIMER,
    2487           0 :                                       nhgr->unbalanced_timer * 1000);
    2488           0 :                         nl_attr_nest_end(n, nest);
    2489             : 
    2490           0 :                         nl_attr_put16(n, req_size, NHA_GROUP_TYPE,
    2491             :                                       NEXTHOP_GRP_TYPE_RES);
    2492             :                 }
    2493             :         }
    2494             : 
    2495           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    2496           0 :                 zlog_debug("%s: ID (%u): %s", __func__, id, buf);
    2497             : 
    2498             :         return true;
    2499             : }
    2500             : 
    2501             : /**
    2502             :  * Next hop packet encoding helper function.
    2503             :  *
    2504             :  * \param[in] cmd netlink command.
    2505             :  * \param[in] ctx dataplane context (information snapshot).
    2506             :  * \param[out] buf buffer to hold the packet.
    2507             :  * \param[in] buflen amount of buffer bytes.
    2508             :  *
    2509             :  * \returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
    2510             :  * otherwise the number of bytes written to buf.
    2511             :  */
    2512          50 : ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
    2513             :                                    const struct zebra_dplane_ctx *ctx,
    2514             :                                    void *buf, size_t buflen, bool fpm)
    2515             : {
    2516          50 :         struct {
    2517             :                 struct nlmsghdr n;
    2518             :                 struct nhmsg nhm;
    2519             :                 char buf[];
    2520          50 :         } *req = buf;
    2521             : 
    2522          50 :         mpls_lse_t out_lse[MPLS_MAX_LABELS];
    2523          50 :         char label_buf[256];
    2524          50 :         int num_labels = 0;
    2525          50 :         uint32_t id = dplane_ctx_get_nhe_id(ctx);
    2526          50 :         int type = dplane_ctx_get_nhe_type(ctx);
    2527          50 :         struct rtattr *nest;
    2528          50 :         uint16_t encap;
    2529          50 :         struct nlsock *nl =
    2530          50 :                 kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
    2531             : 
    2532          50 :         if (!id) {
    2533           0 :                 flog_err(
    2534             :                         EC_ZEBRA_NHG_FIB_UPDATE,
    2535             :                         "Failed trying to update a nexthop group in the kernel that does not have an ID");
    2536           0 :                 return -1;
    2537             :         }
    2538             : 
    2539             :         /*
    2540             :          * Nothing to do if the kernel doesn't support nexthop objects or
    2541             :          * we dont want to install this type of NHG, but FPM may possible to
    2542             :          * handle this.
    2543             :          */
    2544          50 :         if (!fpm && !kernel_nexthops_supported()) {
    2545           0 :                 if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
    2546           0 :                         zlog_debug(
    2547             :                                 "%s: nhg_id %u (%s): kernel nexthops not supported, ignoring",
    2548             :                                 __func__, id, zebra_route_string(type));
    2549           0 :                 return 0;
    2550             :         }
    2551             : 
    2552          50 :         if (proto_nexthops_only() && !is_proto_nhg(id, type)) {
    2553           0 :                 if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
    2554           0 :                         zlog_debug(
    2555             :                                 "%s: nhg_id %u (%s): proto-based nexthops only, ignoring",
    2556             :                                 __func__, id, zebra_route_string(type));
    2557           0 :                 return 0;
    2558             :         }
    2559             : 
    2560          50 :         label_buf[0] = '\0';
    2561             : 
    2562          50 :         if (buflen < sizeof(*req))
    2563             :                 return 0;
    2564             : 
    2565          50 :         memset(req, 0, sizeof(*req));
    2566             : 
    2567          50 :         req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
    2568          50 :         req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
    2569             : 
    2570          50 :         if (cmd == RTM_NEWNEXTHOP)
    2571          30 :                 req->n.nlmsg_flags |= NLM_F_REPLACE;
    2572             : 
    2573          50 :         req->n.nlmsg_type = cmd;
    2574          50 :         req->n.nlmsg_pid = nl->snl.nl_pid;
    2575             : 
    2576          50 :         req->nhm.nh_family = AF_UNSPEC;
    2577             :         /* TODO: Scope? */
    2578             : 
    2579          50 :         if (!nl_attr_put32(&req->n, buflen, NHA_ID, id))
    2580             :                 return 0;
    2581             : 
    2582          50 :         if (cmd == RTM_NEWNEXTHOP) {
    2583             :                 /*
    2584             :                  * We distinguish between a "group", which is a collection
    2585             :                  * of ids, and a singleton nexthop with an id. The
    2586             :                  * group is installed as an id that just refers to a list of
    2587             :                  * other ids.
    2588             :                  */
    2589          30 :                 if (dplane_ctx_get_nhe_nh_grp_count(ctx)) {
    2590           0 :                         const struct nexthop_group *nhg;
    2591           0 :                         const struct nhg_resilience *nhgr;
    2592             : 
    2593           0 :                         nhg = dplane_ctx_get_nhe_ng(ctx);
    2594           0 :                         nhgr = &nhg->nhgr;
    2595           0 :                         if (!_netlink_nexthop_build_group(
    2596             :                                     &req->n, buflen, id,
    2597             :                                     dplane_ctx_get_nhe_nh_grp(ctx),
    2598           0 :                                     dplane_ctx_get_nhe_nh_grp_count(ctx),
    2599           0 :                                     !!nhgr->buckets, nhgr))
    2600             :                                 return 0;
    2601             :                 } else {
    2602          60 :                         const struct nexthop *nh =
    2603          30 :                                 dplane_ctx_get_nhe_ng(ctx)->nexthop;
    2604          30 :                         afi_t afi = dplane_ctx_get_nhe_afi(ctx);
    2605             : 
    2606          30 :                         if (afi == AFI_IP)
    2607          16 :                                 req->nhm.nh_family = AF_INET;
    2608          14 :                         else if (afi == AFI_IP6)
    2609          14 :                                 req->nhm.nh_family = AF_INET6;
    2610             : 
    2611          30 :                         switch (nh->type) {
    2612           2 :                         case NEXTHOP_TYPE_IPV4:
    2613             :                         case NEXTHOP_TYPE_IPV4_IFINDEX:
    2614           2 :                                 if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
    2615           2 :                                                  &nh->gate.ipv4,
    2616             :                                                  IPV4_MAX_BYTELEN))
    2617             :                                         return 0;
    2618             :                                 break;
    2619           0 :                         case NEXTHOP_TYPE_IPV6:
    2620             :                         case NEXTHOP_TYPE_IPV6_IFINDEX:
    2621           0 :                                 if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
    2622           0 :                                                  &nh->gate.ipv6,
    2623             :                                                  IPV6_MAX_BYTELEN))
    2624             :                                         return 0;
    2625             :                                 break;
    2626           0 :                         case NEXTHOP_TYPE_BLACKHOLE:
    2627           0 :                                 if (!nl_attr_put(&req->n, buflen, NHA_BLACKHOLE,
    2628             :                                                  NULL, 0))
    2629             :                                         return 0;
    2630             :                                 /* Blackhole shouldn't have anymore attributes
    2631             :                                  */
    2632           0 :                                 goto nexthop_done;
    2633             :                         case NEXTHOP_TYPE_IFINDEX:
    2634             :                                 /* Don't need anymore info for this */
    2635             :                                 break;
    2636             :                         }
    2637             : 
    2638          30 :                         if (!nh->ifindex) {
    2639           0 :                                 flog_err(
    2640             :                                         EC_ZEBRA_NHG_FIB_UPDATE,
    2641             :                                         "Context received for kernel nexthop update without an interface");
    2642           0 :                                 return -1;
    2643             :                         }
    2644             : 
    2645          30 :                         if (!nl_attr_put32(&req->n, buflen, NHA_OIF,
    2646             :                                            nh->ifindex))
    2647             :                                 return 0;
    2648             : 
    2649          30 :                         if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
    2650           0 :                                 req->nhm.nh_flags |= RTNH_F_ONLINK;
    2651             : 
    2652          30 :                         num_labels =
    2653          30 :                                 build_label_stack(nh->nh_label, out_lse,
    2654             :                                                   label_buf, sizeof(label_buf));
    2655             : 
    2656          30 :                         if (num_labels) {
    2657             :                                 /* Set the BoS bit */
    2658           0 :                                 out_lse[num_labels - 1] |=
    2659           0 :                                         htonl(1 << MPLS_LS_S_SHIFT);
    2660             : 
    2661             :                                 /*
    2662             :                                  * TODO: MPLS unsupported for now in kernel.
    2663             :                                  */
    2664           0 :                                 if (req->nhm.nh_family == AF_MPLS)
    2665           0 :                                         goto nexthop_done;
    2666             : 
    2667           0 :                                 encap = LWTUNNEL_ENCAP_MPLS;
    2668           0 :                                 if (!nl_attr_put16(&req->n, buflen,
    2669             :                                                    NHA_ENCAP_TYPE, encap))
    2670             :                                         return 0;
    2671           0 :                                 nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP);
    2672           0 :                                 if (!nest)
    2673             :                                         return 0;
    2674           0 :                                 if (!nl_attr_put(
    2675             :                                             &req->n, buflen, MPLS_IPTUNNEL_DST,
    2676             :                                             &out_lse,
    2677             :                                             num_labels * sizeof(mpls_lse_t)))
    2678             :                                         return 0;
    2679             : 
    2680           0 :                                 nl_attr_nest_end(&req->n, nest);
    2681             :                         }
    2682             : 
    2683          30 :                         if (nh->nh_srv6) {
    2684           0 :                                 if (nh->nh_srv6->seg6local_action !=
    2685             :                                     ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
    2686           0 :                                         uint32_t action;
    2687           0 :                                         uint16_t encap;
    2688           0 :                                         struct rtattr *nest;
    2689           0 :                                         const struct seg6local_context *ctx;
    2690             : 
    2691           0 :                                         req->nhm.nh_family = AF_INET6;
    2692           0 :                                         action = nh->nh_srv6->seg6local_action;
    2693           0 :                                         ctx = &nh->nh_srv6->seg6local_ctx;
    2694           0 :                                         encap = LWTUNNEL_ENCAP_SEG6_LOCAL;
    2695           0 :                                         if (!nl_attr_put(&req->n, buflen,
    2696             :                                                          NHA_ENCAP_TYPE,
    2697             :                                                          &encap,
    2698             :                                                          sizeof(uint16_t)))
    2699           0 :                                                 return 0;
    2700             : 
    2701           0 :                                         nest = nl_attr_nest(&req->n, buflen,
    2702             :                                                 NHA_ENCAP | NLA_F_NESTED);
    2703           0 :                                         if (!nest)
    2704             :                                                 return 0;
    2705             : 
    2706           0 :                                         switch (action) {
    2707           0 :                                         case SEG6_LOCAL_ACTION_END:
    2708           0 :                                                 if (!nl_attr_put32(
    2709             :                                                     &req->n, buflen,
    2710             :                                                     SEG6_LOCAL_ACTION,
    2711             :                                                     SEG6_LOCAL_ACTION_END))
    2712             :                                                         return 0;
    2713             :                                                 break;
    2714           0 :                                         case SEG6_LOCAL_ACTION_END_X:
    2715           0 :                                                 if (!nl_attr_put32(
    2716             :                                                     &req->n, buflen,
    2717             :                                                     SEG6_LOCAL_ACTION,
    2718             :                                                     SEG6_LOCAL_ACTION_END_X))
    2719             :                                                         return 0;
    2720           0 :                                                 if (!nl_attr_put(
    2721             :                                                     &req->n, buflen,
    2722           0 :                                                     SEG6_LOCAL_NH6, &ctx->nh6,
    2723             :                                                     sizeof(struct in6_addr)))
    2724             :                                                         return 0;
    2725             :                                                 break;
    2726           0 :                                         case SEG6_LOCAL_ACTION_END_T:
    2727           0 :                                                 if (!nl_attr_put32(
    2728             :                                                     &req->n, buflen,
    2729             :                                                     SEG6_LOCAL_ACTION,
    2730             :                                                     SEG6_LOCAL_ACTION_END_T))
    2731             :                                                         return 0;
    2732           0 :                                                 if (!nl_attr_put32(
    2733             :                                                     &req->n, buflen,
    2734             :                                                     SEG6_LOCAL_TABLE,
    2735           0 :                                                     ctx->table))
    2736             :                                                         return 0;
    2737             :                                                 break;
    2738           0 :                                         case SEG6_LOCAL_ACTION_END_DX4:
    2739           0 :                                                 if (!nl_attr_put32(
    2740             :                                                     &req->n, buflen,
    2741             :                                                     SEG6_LOCAL_ACTION,
    2742             :                                                     SEG6_LOCAL_ACTION_END_DX4))
    2743             :                                                         return 0;
    2744           0 :                                                 if (!nl_attr_put(
    2745             :                                                     &req->n, buflen,
    2746           0 :                                                     SEG6_LOCAL_NH4, &ctx->nh4,
    2747             :                                                     sizeof(struct in_addr)))
    2748             :                                                         return 0;
    2749             :                                                 break;
    2750           0 :                                         case SEG6_LOCAL_ACTION_END_DT6:
    2751           0 :                                                 if (!nl_attr_put32(
    2752             :                                                     &req->n, buflen,
    2753             :                                                     SEG6_LOCAL_ACTION,
    2754             :                                                     SEG6_LOCAL_ACTION_END_DT6))
    2755             :                                                         return 0;
    2756           0 :                                                 if (!nl_attr_put32(
    2757             :                                                     &req->n, buflen,
    2758             :                                                     SEG6_LOCAL_TABLE,
    2759           0 :                                                     ctx->table))
    2760             :                                                         return 0;
    2761             :                                                 break;
    2762           0 :                                         case SEG6_LOCAL_ACTION_END_DT4:
    2763           0 :                                                 if (!nl_attr_put32(
    2764             :                                                             &req->n, buflen,
    2765             :                                                             SEG6_LOCAL_ACTION,
    2766             :                                                             SEG6_LOCAL_ACTION_END_DT4))
    2767             :                                                         return 0;
    2768           0 :                                                 if (!nl_attr_put32(
    2769             :                                                             &req->n, buflen,
    2770             :                                                             SEG6_LOCAL_VRFTABLE,
    2771           0 :                                                             ctx->table))
    2772             :                                                         return 0;
    2773             :                                                 break;
    2774           0 :                                         case SEG6_LOCAL_ACTION_END_DT46:
    2775           0 :                                                 if (!nl_attr_put32(
    2776             :                                                             &req->n, buflen,
    2777             :                                                             SEG6_LOCAL_ACTION,
    2778             :                                                             SEG6_LOCAL_ACTION_END_DT46))
    2779             :                                                         return 0;
    2780           0 :                                                 if (!nl_attr_put32(
    2781             :                                                             &req->n, buflen,
    2782             :                                                             SEG6_LOCAL_VRFTABLE,
    2783           0 :                                                             ctx->table))
    2784             :                                                         return 0;
    2785             :                                                 break;
    2786           0 :                                         default:
    2787           0 :                                                 zlog_err("%s: unsupport seg6local behaviour action=%u",
    2788             :                                                          __func__, action);
    2789           0 :                                                 return 0;
    2790             :                                         }
    2791           0 :                                         nl_attr_nest_end(&req->n, nest);
    2792             :                                 }
    2793             : 
    2794           0 :                                 if (!sid_zero(&nh->nh_srv6->seg6_segs)) {
    2795           0 :                                         char tun_buf[4096];
    2796           0 :                                         ssize_t tun_len;
    2797           0 :                                         struct rtattr *nest;
    2798             : 
    2799           0 :                                         if (!nl_attr_put16(&req->n, buflen,
    2800             :                                             NHA_ENCAP_TYPE,
    2801             :                                             LWTUNNEL_ENCAP_SEG6))
    2802           0 :                                                 return 0;
    2803           0 :                                         nest = nl_attr_nest(&req->n, buflen,
    2804             :                                             NHA_ENCAP | NLA_F_NESTED);
    2805           0 :                                         if (!nest)
    2806             :                                                 return 0;
    2807           0 :                                         tun_len = fill_seg6ipt_encap(tun_buf,
    2808             :                                             sizeof(tun_buf),
    2809           0 :                                             &nh->nh_srv6->seg6_segs);
    2810           0 :                                         if (tun_len < 0)
    2811             :                                                 return 0;
    2812           0 :                                         if (!nl_attr_put(&req->n, buflen,
    2813             :                                                          SEG6_IPTUNNEL_SRH,
    2814             :                                                          tun_buf, tun_len))
    2815             :                                                 return 0;
    2816           0 :                                         nl_attr_nest_end(&req->n, nest);
    2817             :                                 }
    2818             :                         }
    2819             : 
    2820          30 : nexthop_done:
    2821             : 
    2822          30 :                         if (IS_ZEBRA_DEBUG_KERNEL)
    2823           0 :                                 zlog_debug("%s: ID (%u): %pNHv(%d) vrf %s(%u) %s ",
    2824             :                                            __func__, id, nh, nh->ifindex,
    2825             :                                            vrf_id_to_name(nh->vrf_id),
    2826             :                                            nh->vrf_id, label_buf);
    2827             :                 }
    2828             : 
    2829          30 :                 req->nhm.nh_protocol = zebra2proto(type);
    2830             : 
    2831          20 :         } else if (cmd != RTM_DELNEXTHOP) {
    2832           0 :                 flog_err(
    2833             :                         EC_ZEBRA_NHG_FIB_UPDATE,
    2834             :                         "Nexthop group kernel update command (%d) does not exist",
    2835             :                         cmd);
    2836           0 :                 return -1;
    2837             :         }
    2838             : 
    2839          50 :         if (IS_ZEBRA_DEBUG_KERNEL)
    2840           0 :                 zlog_debug("%s: %s, id=%u", __func__, nl_msg_type_to_str(cmd),
    2841             :                            id);
    2842             : 
    2843          50 :         return NLMSG_ALIGN(req->n.nlmsg_len);
    2844             : }
    2845             : 
    2846          50 : static ssize_t netlink_nexthop_msg_encoder(struct zebra_dplane_ctx *ctx,
    2847             :                                            void *buf, size_t buflen)
    2848             : {
    2849          50 :         enum dplane_op_e op;
    2850          50 :         int cmd = 0;
    2851             : 
    2852          50 :         op = dplane_ctx_get_op(ctx);
    2853          50 :         if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
    2854             :                 cmd = RTM_NEWNEXTHOP;
    2855          20 :         else if (op == DPLANE_OP_NH_DELETE)
    2856             :                 cmd = RTM_DELNEXTHOP;
    2857             :         else {
    2858           0 :                 flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
    2859             :                          "Context received for kernel nexthop update with incorrect OP code (%u)",
    2860             :                          op);
    2861           0 :                 return -1;
    2862             :         }
    2863             : 
    2864          50 :         return netlink_nexthop_msg_encode(cmd, ctx, buf, buflen, false);
    2865             : }
    2866             : 
    2867             : enum netlink_msg_status
    2868          50 : netlink_put_nexthop_update_msg(struct nl_batch *bth,
    2869             :                                struct zebra_dplane_ctx *ctx)
    2870             : {
    2871             :         /* Nothing to do if the kernel doesn't support nexthop objects */
    2872          50 :         if (!kernel_nexthops_supported())
    2873             :                 return FRR_NETLINK_SUCCESS;
    2874             : 
    2875          50 :         return netlink_batch_add_msg(bth, ctx, netlink_nexthop_msg_encoder,
    2876             :                                      false);
    2877             : }
    2878             : 
    2879           4 : static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx,
    2880             :                                             void *buf, size_t buflen)
    2881             : {
    2882           4 :         return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf,
    2883             :                                                   buflen, false, false);
    2884             : }
    2885             : 
    2886           3 : static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx,
    2887             :                                             void *buf, size_t buflen)
    2888             : {
    2889           3 :         return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf,
    2890             :                                                   buflen, false, false);
    2891             : }
    2892             : 
    2893             : enum netlink_msg_status
    2894          74 : netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
    2895             : {
    2896          74 :         int cmd;
    2897          74 :         const struct prefix *p = dplane_ctx_get_dest(ctx);
    2898             : 
    2899          74 :         if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
    2900             :                 cmd = RTM_DELROUTE;
    2901          39 :         } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
    2902             :                 cmd = RTM_NEWROUTE;
    2903           1 :         } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
    2904             : 
    2905           1 :                 if (p->family == AF_INET || v6_rr_semantics) {
    2906             :                         /* Single 'replace' operation */
    2907             : 
    2908             :                         /*
    2909             :                          * With route replace semantics in place
    2910             :                          * for v4 routes and the new route is a system
    2911             :                          * route we do not install anything.
    2912             :                          * The problem here is that the new system
    2913             :                          * route should cause us to withdraw from
    2914             :                          * the kernel the old non-system route
    2915             :                          */
    2916           1 :                         if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))
    2917           0 :                             && !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
    2918           0 :                                 return netlink_batch_add_msg(
    2919             :                                         bth, ctx, netlink_delroute_msg_encoder,
    2920             :                                         true);
    2921             :                 } else {
    2922             :                         /*
    2923             :                          * So v6 route replace semantics are not in
    2924             :                          * the kernel at this point as I understand it.
    2925             :                          * so let's do a delete then an add.
    2926             :                          * In the future once v6 route replace semantics
    2927             :                          * are in we can figure out what to do here to
    2928             :                          * allow working with old and new kernels.
    2929             :                          *
    2930             :                          * I'm also intentionally ignoring the failure case
    2931             :                          * of the route delete.  If that happens yeah we're
    2932             :                          * screwed.
    2933             :                          */
    2934           0 :                         if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
    2935           0 :                                 netlink_batch_add_msg(
    2936             :                                         bth, ctx, netlink_delroute_msg_encoder,
    2937             :                                         true);
    2938             :                 }
    2939             : 
    2940             :                 cmd = RTM_NEWROUTE;
    2941             :         } else
    2942             :                 return FRR_NETLINK_ERROR;
    2943             : 
    2944          74 :         if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
    2945          67 :                 return FRR_NETLINK_SUCCESS;
    2946             : 
    2947          10 :         return netlink_batch_add_msg(bth, ctx,
    2948             :                                      cmd == RTM_NEWROUTE
    2949             :                                              ? netlink_newroute_msg_encoder
    2950             :                                              : netlink_delroute_msg_encoder,
    2951             :                                      false);
    2952             : }
    2953             : 
    2954             : /**
    2955             :  * netlink_nexthop_process_nh() - Parse the gatway/if info from a new nexthop
    2956             :  *
    2957             :  * @tb:         Netlink RTA data
    2958             :  * @family:     Address family in the nhmsg
    2959             :  * @ifp:        Interface connected - this should be NULL, we fill it in
    2960             :  * @ns_id:      Namspace id
    2961             :  *
    2962             :  * Return:      New nexthop
    2963             :  */
    2964           0 : static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
    2965             :                                                  unsigned char family,
    2966             :                                                  struct interface **ifp,
    2967             :                                                  ns_id_t ns_id)
    2968             : {
    2969           0 :         struct nexthop nh = {};
    2970           0 :         void *gate = NULL;
    2971           0 :         enum nexthop_types_t type = 0;
    2972           0 :         int if_index = 0;
    2973           0 :         size_t sz = 0;
    2974           0 :         struct interface *ifp_lookup;
    2975             : 
    2976           0 :         if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
    2977             : 
    2978             : 
    2979           0 :         if (tb[NHA_GATEWAY]) {
    2980           0 :                 switch (family) {
    2981             :                 case AF_INET:
    2982             :                         type = NEXTHOP_TYPE_IPV4_IFINDEX;
    2983             :                         sz = 4;
    2984             :                         break;
    2985           0 :                 case AF_INET6:
    2986           0 :                         type = NEXTHOP_TYPE_IPV6_IFINDEX;
    2987           0 :                         sz = 16;
    2988           0 :                         break;
    2989           0 :                 default:
    2990           0 :                         flog_warn(
    2991             :                                 EC_ZEBRA_BAD_NHG_MESSAGE,
    2992             :                                 "Nexthop gateway with bad address family (%d) received from kernel",
    2993             :                                 family);
    2994           0 :                         return nh;
    2995             :                 }
    2996           0 :                 gate = RTA_DATA(tb[NHA_GATEWAY]);
    2997             :         } else
    2998             :                 type = NEXTHOP_TYPE_IFINDEX;
    2999             : 
    3000           0 :         if (type)
    3001           0 :                 nh.type = type;
    3002             : 
    3003           0 :         if (gate)
    3004           0 :                 memcpy(&(nh.gate), gate, sz);
    3005             : 
    3006           0 :         if (if_index)
    3007           0 :                 nh.ifindex = if_index;
    3008             : 
    3009           0 :         ifp_lookup =
    3010           0 :                 if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
    3011             : 
    3012           0 :         if (ifp)
    3013           0 :                 *ifp = ifp_lookup;
    3014           0 :         if (ifp_lookup)
    3015           0 :                 nh.vrf_id = ifp_lookup->vrf->vrf_id;
    3016             :         else {
    3017           0 :                 flog_warn(
    3018             :                         EC_ZEBRA_UNKNOWN_INTERFACE,
    3019             :                         "%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT",
    3020             :                         __func__, nh.ifindex);
    3021             : 
    3022           0 :                 nh.vrf_id = VRF_DEFAULT;
    3023             :         }
    3024             : 
    3025           0 :         if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
    3026           0 :                 uint16_t encap_type = *(uint16_t *)RTA_DATA(tb[NHA_ENCAP_TYPE]);
    3027           0 :                 int num_labels = 0;
    3028             : 
    3029           0 :                 mpls_label_t labels[MPLS_MAX_LABELS] = {0};
    3030             : 
    3031           0 :                 if (encap_type == LWTUNNEL_ENCAP_MPLS)
    3032           0 :                         num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels);
    3033             : 
    3034           0 :                 if (num_labels)
    3035           0 :                         nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels,
    3036             :                                            labels);
    3037             :         }
    3038             : 
    3039           0 :         return nh;
    3040             : }
    3041             : 
    3042           0 : static int netlink_nexthop_process_group(struct rtattr **tb,
    3043             :                                          struct nh_grp *z_grp, int z_grp_size,
    3044             :                                          struct nhg_resilience *nhgr)
    3045             : {
    3046           0 :         uint8_t count = 0;
    3047             :         /* linux/nexthop.h group struct */
    3048           0 :         struct nexthop_grp *n_grp = NULL;
    3049             : 
    3050           0 :         n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
    3051           0 :         count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp));
    3052             : 
    3053           0 :         if (!count || (count * sizeof(*n_grp)) != RTA_PAYLOAD(tb[NHA_GROUP])) {
    3054           0 :                 flog_warn(EC_ZEBRA_BAD_NHG_MESSAGE,
    3055             :                           "Invalid nexthop group received from the kernel");
    3056           0 :                 return count;
    3057             :         }
    3058             : 
    3059           0 :         for (int i = 0; ((i < count) && (i < z_grp_size)); i++) {
    3060           0 :                 z_grp[i].id = n_grp[i].id;
    3061           0 :                 z_grp[i].weight = n_grp[i].weight + 1;
    3062             :         }
    3063             : 
    3064           0 :         memset(nhgr, 0, sizeof(*nhgr));
    3065           0 :         if (tb[NHA_RES_GROUP]) {
    3066           0 :                 struct rtattr *tbn[NHA_RES_GROUP_MAX + 1];
    3067           0 :                 struct rtattr *rta;
    3068           0 :                 struct rtattr *res_group = tb[NHA_RES_GROUP];
    3069             : 
    3070           0 :                 netlink_parse_rtattr_nested(tbn, NHA_RES_GROUP_MAX, res_group);
    3071             : 
    3072           0 :                 if (tbn[NHA_RES_GROUP_BUCKETS]) {
    3073           0 :                         rta = tbn[NHA_RES_GROUP_BUCKETS];
    3074           0 :                         nhgr->buckets = *(uint16_t *)RTA_DATA(rta);
    3075             :                 }
    3076             : 
    3077           0 :                 if (tbn[NHA_RES_GROUP_IDLE_TIMER]) {
    3078           0 :                         rta = tbn[NHA_RES_GROUP_IDLE_TIMER];
    3079           0 :                         nhgr->idle_timer = *(uint32_t *)RTA_DATA(rta);
    3080             :                 }
    3081             : 
    3082           0 :                 if (tbn[NHA_RES_GROUP_UNBALANCED_TIMER]) {
    3083           0 :                         rta = tbn[NHA_RES_GROUP_UNBALANCED_TIMER];
    3084           0 :                         nhgr->unbalanced_timer = *(uint32_t *)RTA_DATA(rta);
    3085             :                 }
    3086             : 
    3087           0 :                 if (tbn[NHA_RES_GROUP_UNBALANCED_TIME]) {
    3088           0 :                         rta = tbn[NHA_RES_GROUP_UNBALANCED_TIME];
    3089           0 :                         nhgr->unbalanced_time = *(uint64_t *)RTA_DATA(rta);
    3090             :                 }
    3091             :         }
    3092             : 
    3093             :         return count;
    3094             : }
    3095             : 
    3096             : /**
    3097             :  * netlink_nexthop_change() - Read in change about nexthops from the kernel
    3098             :  *
    3099             :  * @h:          Netlink message header
    3100             :  * @ns_id:      Namspace id
    3101             :  * @startup:    Are we reading under startup conditions?
    3102             :  *
    3103             :  * Return:      Result status
    3104             :  */
    3105           0 : int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
    3106             : {
    3107           0 :         int len;
    3108             :         /* nexthop group id */
    3109           0 :         uint32_t id;
    3110           0 :         unsigned char family;
    3111           0 :         int type;
    3112           0 :         afi_t afi = AFI_UNSPEC;
    3113           0 :         vrf_id_t vrf_id = VRF_DEFAULT;
    3114           0 :         struct interface *ifp = NULL;
    3115           0 :         struct nhmsg *nhm = NULL;
    3116           0 :         struct nexthop nh = {};
    3117           0 :         struct nh_grp grp[MULTIPATH_NUM] = {};
    3118             :         /* Count of nexthops in group array */
    3119           0 :         uint8_t grp_count = 0;
    3120           0 :         struct rtattr *tb[NHA_MAX + 1] = {};
    3121             : 
    3122           0 :         frrtrace(3, frr_zebra, netlink_nexthop_change, h, ns_id, startup);
    3123             : 
    3124           0 :         nhm = NLMSG_DATA(h);
    3125             : 
    3126           0 :         if (ns_id)
    3127             :                 vrf_id = ns_id;
    3128             : 
    3129           0 :         if (startup && h->nlmsg_type != RTM_NEWNEXTHOP)
    3130             :                 return 0;
    3131             : 
    3132           0 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct nhmsg));
    3133           0 :         if (len < 0) {
    3134           0 :                 zlog_warn(
    3135             :                         "%s: Message received from netlink is of a broken size %d %zu",
    3136             :                         __func__, h->nlmsg_len,
    3137             :                         (size_t)NLMSG_LENGTH(sizeof(struct nhmsg)));
    3138           0 :                 return -1;
    3139             :         }
    3140             : 
    3141           0 :         netlink_parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len,
    3142             :                                    NLA_F_NESTED);
    3143             : 
    3144             : 
    3145           0 :         if (!tb[NHA_ID]) {
    3146           0 :                 flog_warn(
    3147             :                         EC_ZEBRA_BAD_NHG_MESSAGE,
    3148             :                         "Nexthop group without an ID received from the kernel");
    3149           0 :                 return -1;
    3150             :         }
    3151             : 
    3152             :         /* We use the ID key'd nhg table for kernel updates */
    3153           0 :         id = *((uint32_t *)RTA_DATA(tb[NHA_ID]));
    3154             : 
    3155           0 :         if (zebra_evpn_mh_is_fdb_nh(id)) {
    3156             :                 /* If this is a L2 NH just ignore it */
    3157           0 :                 if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
    3158           0 :                         zlog_debug("Ignore kernel update (%u) for fdb-nh 0x%x",
    3159             :                                         h->nlmsg_type, id);
    3160             :                 }
    3161           0 :                 return 0;
    3162             :         }
    3163             : 
    3164           0 :         family = nhm->nh_family;
    3165           0 :         afi = family2afi(family);
    3166             : 
    3167           0 :         type = proto2zebra(nhm->nh_protocol, 0, true);
    3168             : 
    3169           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    3170           0 :                 zlog_debug("%s ID (%u) %s NS %u",
    3171             :                            nl_msg_type_to_str(h->nlmsg_type), id,
    3172             :                            nl_family_to_str(family), ns_id);
    3173             : 
    3174             : 
    3175           0 :         if (h->nlmsg_type == RTM_NEWNEXTHOP) {
    3176           0 :                 struct nhg_resilience nhgr = {};
    3177             : 
    3178           0 :                 if (tb[NHA_GROUP]) {
    3179             :                         /**
    3180             :                          * If this is a group message its only going to have
    3181             :                          * an array of nexthop IDs associated with it
    3182             :                          */
    3183           0 :                         grp_count = netlink_nexthop_process_group(
    3184             :                                 tb, grp, array_size(grp), &nhgr);
    3185             :                 } else {
    3186           0 :                         if (tb[NHA_BLACKHOLE]) {
    3187             :                                 /**
    3188             :                                  * This nexthop is just for blackhole-ing
    3189             :                                  * traffic, it should not have an OIF, GATEWAY,
    3190             :                                  * or ENCAP
    3191             :                                  */
    3192           0 :                                 nh.type = NEXTHOP_TYPE_BLACKHOLE;
    3193           0 :                                 nh.bh_type = BLACKHOLE_UNSPEC;
    3194           0 :                         } else if (tb[NHA_OIF])
    3195             :                                 /**
    3196             :                                  * This is a true new nexthop, so we need
    3197             :                                  * to parse the gateway and device info
    3198             :                                  */
    3199           0 :                                 nh = netlink_nexthop_process_nh(tb, family,
    3200             :                                                                 &ifp, ns_id);
    3201             :                         else {
    3202             : 
    3203           0 :                                 flog_warn(
    3204             :                                         EC_ZEBRA_BAD_NHG_MESSAGE,
    3205             :                                         "Invalid Nexthop message received from the kernel with ID (%u)",
    3206             :                                         id);
    3207           0 :                                 return -1;
    3208             :                         }
    3209           0 :                         SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE);
    3210           0 :                         if (nhm->nh_flags & RTNH_F_ONLINK)
    3211           0 :                                 SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
    3212           0 :                         vrf_id = nh.vrf_id;
    3213             :                 }
    3214             : 
    3215           0 :                 if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi,
    3216             :                                           type, startup, &nhgr))
    3217             :                         return -1;
    3218             : 
    3219           0 :         } else if (h->nlmsg_type == RTM_DELNEXTHOP)
    3220           0 :                 zebra_nhg_kernel_del(id, vrf_id);
    3221             : 
    3222             :         return 0;
    3223             : }
    3224             : 
    3225             : /**
    3226             :  * netlink_request_nexthop() - Request nextop information from the kernel
    3227             :  * @zns:        Zebra namespace
    3228             :  * @family:     AF_* netlink family
    3229             :  * @type:       RTM_* route type
    3230             :  *
    3231             :  * Return:      Result status
    3232             :  */
    3233           4 : static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type)
    3234             : {
    3235           4 :         struct {
    3236             :                 struct nlmsghdr n;
    3237             :                 struct nhmsg nhm;
    3238             :         } req;
    3239             : 
    3240             :         /* Form the request, specifying filter (rtattr) if needed. */
    3241           4 :         memset(&req, 0, sizeof(req));
    3242           4 :         req.n.nlmsg_type = type;
    3243           4 :         req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
    3244           4 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
    3245           4 :         req.nhm.nh_family = family;
    3246             : 
    3247           4 :         return netlink_request(&zns->netlink_cmd, &req);
    3248             : }
    3249             : 
    3250             : 
    3251             : /**
    3252             :  * netlink_nexthop_read() - Nexthop read function using netlink interface
    3253             :  *
    3254             :  * @zns:        Zebra name space
    3255             :  *
    3256             :  * Return:      Result status
    3257             :  * Only called at bootstrap time.
    3258             :  */
    3259           4 : int netlink_nexthop_read(struct zebra_ns *zns)
    3260             : {
    3261           4 :         int ret;
    3262           4 :         struct zebra_dplane_info dp_info;
    3263             : 
    3264           4 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    3265             : 
    3266             :         /* Get nexthop objects */
    3267           4 :         ret = netlink_request_nexthop(zns, AF_UNSPEC, RTM_GETNEXTHOP);
    3268           4 :         if (ret < 0)
    3269             :                 return ret;
    3270           4 :         ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd,
    3271             :                                  &dp_info, 0, true);
    3272             : 
    3273           4 :         if (!ret)
    3274             :                 /* If we succesfully read in nexthop objects,
    3275             :                  * this kernel must support them.
    3276             :                  */
    3277           4 :                 supports_nh = true;
    3278           4 :         if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
    3279           0 :                 zlog_debug("Nexthop objects %ssupported on this kernel",
    3280             :                            supports_nh ? "" : "not ");
    3281             : 
    3282           4 :         zebra_router_set_supports_nhgs(supports_nh);
    3283             : 
    3284           4 :         return ret;
    3285             : }
    3286             : 
    3287             : 
    3288           0 : int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
    3289             :                         ns_id_t ns_id, uint8_t family, bool permanent)
    3290             : {
    3291           0 :         return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex,
    3292             :                                     addr, lla, llalen, ns_id, family, permanent,
    3293             :                                     RTPROT_ZEBRA);
    3294             : }
    3295             : 
    3296             : /**
    3297             :  * netlink_neigh_update_msg_encode() - Common helper api for encoding
    3298             :  * evpn neighbor update as netlink messages using dataplane context object.
    3299             :  * Here, a neighbor refers to a bridge forwarding database entry for
    3300             :  * either unicast forwarding or head-end replication or an IP neighbor
    3301             :  * entry.
    3302             :  * @ctx:                Dataplane context
    3303             :  * @cmd:                Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
    3304             :  * @lla:                A pointer to neighbor cache link layer address
    3305             :  * @llalen:             Length of the pointer to neighbor cache link layer
    3306             :  * address
    3307             :  * @ip:         A neighbor cache n/w layer destination address
    3308             :  *                      In the case of bridge FDB, this represnts the remote
    3309             :  *                      VTEP IP.
    3310             :  * @replace_obj:        Whether NEW request should replace existing object or
    3311             :  *                      add to the end of the list
    3312             :  * @family:             AF_* netlink family
    3313             :  * @type:               RTN_* route type
    3314             :  * @flags:              NTF_* flags
    3315             :  * @state:              NUD_* states
    3316             :  * @data:               data buffer pointer
    3317             :  * @datalen:            total amount of data buffer space
    3318             :  * @protocol:           protocol information
    3319             :  *
    3320             :  * Return:              0 when the msg doesn't fit entirely in the buffer
    3321             :  *                              otherwise the number of bytes written to buf.
    3322             :  */
    3323           0 : static ssize_t netlink_neigh_update_msg_encode(
    3324             :         const struct zebra_dplane_ctx *ctx, int cmd, const void *lla,
    3325             :         int llalen, const struct ipaddr *ip, bool replace_obj, uint8_t family,
    3326             :         uint8_t type, uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
    3327             :         uint8_t nfy_flags, bool ext, uint32_t ext_flags, void *data,
    3328             :         size_t datalen, uint8_t protocol)
    3329             : {
    3330           0 :         struct {
    3331             :                 struct nlmsghdr n;
    3332             :                 struct ndmsg ndm;
    3333             :                 char buf[];
    3334           0 :         } *req = data;
    3335           0 :         int ipa_len;
    3336           0 :         enum dplane_op_e op;
    3337             : 
    3338           0 :         if (datalen < sizeof(*req))
    3339             :                 return 0;
    3340           0 :         memset(req, 0, sizeof(*req));
    3341             : 
    3342           0 :         op = dplane_ctx_get_op(ctx);
    3343             : 
    3344           0 :         req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
    3345           0 :         req->n.nlmsg_flags = NLM_F_REQUEST;
    3346           0 :         if (cmd == RTM_NEWNEIGH)
    3347           0 :                 req->n.nlmsg_flags |=
    3348             :                         NLM_F_CREATE
    3349             :                         | (replace_obj ? NLM_F_REPLACE : NLM_F_APPEND);
    3350           0 :         req->n.nlmsg_type = cmd;
    3351           0 :         req->ndm.ndm_family = family;
    3352           0 :         req->ndm.ndm_type = type;
    3353           0 :         req->ndm.ndm_state = state;
    3354           0 :         req->ndm.ndm_flags = flags;
    3355           0 :         req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
    3356             : 
    3357           0 :         if (!nl_attr_put(&req->n, datalen, NDA_PROTOCOL, &protocol,
    3358             :                          sizeof(protocol)))
    3359             :                 return 0;
    3360             : 
    3361           0 :         if (lla) {
    3362           0 :                 if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, lla, llalen))
    3363             :                         return 0;
    3364             :         }
    3365             : 
    3366           0 :         if (nfy) {
    3367           0 :                 struct rtattr *nest;
    3368             : 
    3369           0 :                 nest = nl_attr_nest(&req->n, datalen,
    3370             :                                     NDA_FDB_EXT_ATTRS | NLA_F_NESTED);
    3371           0 :                 if (!nest)
    3372             :                         return 0;
    3373             : 
    3374           0 :                 if (!nl_attr_put(&req->n, datalen, NFEA_ACTIVITY_NOTIFY,
    3375             :                                  &nfy_flags, sizeof(nfy_flags)))
    3376             :                         return 0;
    3377           0 :                 if (!nl_attr_put(&req->n, datalen, NFEA_DONT_REFRESH, NULL, 0))
    3378             :                         return 0;
    3379             : 
    3380           0 :                 nl_attr_nest_end(&req->n, nest);
    3381             :         }
    3382             : 
    3383             : 
    3384           0 :         if (ext) {
    3385           0 :                 if (!nl_attr_put(&req->n, datalen, NDA_EXT_FLAGS, &ext_flags,
    3386             :                                  sizeof(ext_flags)))
    3387             :                         return 0;
    3388             :         }
    3389             : 
    3390           0 :         if (nhg_id) {
    3391           0 :                 if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id))
    3392             :                         return 0;
    3393             :         } else {
    3394           0 :                 ipa_len =
    3395           0 :                         IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
    3396           0 :                 if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr,
    3397             :                                  ipa_len))
    3398             :                         return 0;
    3399             :         }
    3400             : 
    3401           0 :         if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
    3402           0 :                 vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
    3403             : 
    3404           0 :                 if (vid > 0) {
    3405           0 :                         if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid))
    3406             :                                 return 0;
    3407             :                 }
    3408             : 
    3409           0 :                 if (!nl_attr_put32(&req->n, datalen, NDA_MASTER,
    3410           0 :                                    dplane_ctx_mac_get_br_ifindex(ctx)))
    3411             :                         return 0;
    3412             :         }
    3413             : 
    3414           0 :         return NLMSG_ALIGN(req->n.nlmsg_len);
    3415             : }
    3416             : 
    3417             : /*
    3418             :  * Add remote VTEP to the flood list for this VxLAN interface (VNI). This
    3419             :  * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
    3420             :  */
    3421             : static ssize_t
    3422           0 : netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd,
    3423             :                                void *buf, size_t buflen)
    3424             : {
    3425           0 :         struct ethaddr dst_mac = {.octet = {0}};
    3426           0 :         int proto = RTPROT_ZEBRA;
    3427             : 
    3428           0 :         if (dplane_ctx_get_type(ctx) != 0)
    3429           0 :                 proto = zebra2proto(dplane_ctx_get_type(ctx));
    3430             : 
    3431           0 :         return netlink_neigh_update_msg_encode(
    3432             :                 ctx, cmd, (const void *)&dst_mac, ETH_ALEN,
    3433             :                 dplane_ctx_neigh_get_ipaddr(ctx), false, PF_BRIDGE, 0, NTF_SELF,
    3434             :                 (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, false /*nfy*/,
    3435             :                 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/, buf, buflen,
    3436             :                 proto);
    3437             : }
    3438             : 
    3439             : #ifndef NDA_RTA
    3440             : #define NDA_RTA(r)                                                             \
    3441             :         ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
    3442             : #endif
    3443             : 
    3444           0 : static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
    3445             : {
    3446           0 :         struct ndmsg *ndm;
    3447           0 :         struct interface *ifp;
    3448           0 :         struct zebra_if *zif;
    3449           0 :         struct rtattr *tb[NDA_MAX + 1];
    3450           0 :         struct interface *br_if;
    3451           0 :         struct ethaddr mac;
    3452           0 :         vlanid_t vid = 0;
    3453           0 :         struct in_addr vtep_ip;
    3454           0 :         int vid_present = 0, dst_present = 0;
    3455           0 :         char vid_buf[20];
    3456           0 :         char dst_buf[30];
    3457           0 :         bool sticky;
    3458           0 :         bool local_inactive = false;
    3459           0 :         bool dp_static = false;
    3460           0 :         uint32_t nhg_id = 0;
    3461             : 
    3462           0 :         ndm = NLMSG_DATA(h);
    3463             : 
    3464             :         /* We only process macfdb notifications if EVPN is enabled */
    3465           0 :         if (!is_evpn_enabled())
    3466             :                 return 0;
    3467             : 
    3468             :         /* Parse attributes and extract fields of interest. Do basic
    3469             :          * validation of the fields.
    3470             :          */
    3471           0 :         netlink_parse_rtattr_flags(tb, NDA_MAX, NDA_RTA(ndm), len,
    3472             :                                    NLA_F_NESTED);
    3473             : 
    3474           0 :         if (!tb[NDA_LLADDR]) {
    3475           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    3476           0 :                         zlog_debug("%s AF_BRIDGE IF %u - no LLADDR",
    3477             :                                    nl_msg_type_to_str(h->nlmsg_type),
    3478             :                                    ndm->ndm_ifindex);
    3479           0 :                 return 0;
    3480             :         }
    3481             : 
    3482           0 :         if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
    3483           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    3484           0 :                         zlog_debug(
    3485             :                                 "%s AF_BRIDGE IF %u - LLADDR is not MAC, len %lu",
    3486             :                                 nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex,
    3487             :                                 (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
    3488           0 :                 return 0;
    3489             :         }
    3490             : 
    3491           0 :         memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN);
    3492             : 
    3493           0 :         if (tb[NDA_VLAN]) {
    3494           0 :                 vid_present = 1;
    3495           0 :                 vid = *(uint16_t *)RTA_DATA(tb[NDA_VLAN]);
    3496           0 :                 snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid);
    3497             :         }
    3498             : 
    3499           0 :         if (tb[NDA_DST]) {
    3500             :                 /* TODO: Only IPv4 supported now. */
    3501           0 :                 dst_present = 1;
    3502           0 :                 memcpy(&vtep_ip.s_addr, RTA_DATA(tb[NDA_DST]),
    3503             :                        IPV4_MAX_BYTELEN);
    3504           0 :                 snprintfrr(dst_buf, sizeof(dst_buf), " dst %pI4",
    3505             :                            &vtep_ip);
    3506             :         }
    3507             : 
    3508           0 :         if (tb[NDA_NH_ID])
    3509           0 :                 nhg_id = *(uint32_t *)RTA_DATA(tb[NDA_NH_ID]);
    3510             : 
    3511           0 :         if (ndm->ndm_state & NUD_STALE)
    3512           0 :                 local_inactive = true;
    3513             : 
    3514           0 :         if (tb[NDA_FDB_EXT_ATTRS]) {
    3515           0 :                 struct rtattr *attr = tb[NDA_FDB_EXT_ATTRS];
    3516           0 :                 struct rtattr *nfea_tb[NFEA_MAX + 1] = {0};
    3517             : 
    3518           0 :                 netlink_parse_rtattr_nested(nfea_tb, NFEA_MAX, attr);
    3519           0 :                 if (nfea_tb[NFEA_ACTIVITY_NOTIFY]) {
    3520           0 :                         uint8_t nfy_flags;
    3521             : 
    3522           0 :                         nfy_flags = *(uint8_t *)RTA_DATA(
    3523             :                                 nfea_tb[NFEA_ACTIVITY_NOTIFY]);
    3524           0 :                         if (nfy_flags & FDB_NOTIFY_BIT)
    3525           0 :                                 dp_static = true;
    3526           0 :                         if (nfy_flags & FDB_NOTIFY_INACTIVE_BIT)
    3527           0 :                                 local_inactive = true;
    3528             :                 }
    3529             :         }
    3530             : 
    3531           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    3532           0 :                 zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d",
    3533             :                            nl_msg_type_to_str(h->nlmsg_type),
    3534             :                            ndm->ndm_ifindex, vid_present ? vid_buf : "",
    3535             :                            ndm->ndm_state, ndm->ndm_flags, &mac,
    3536             :                            dst_present ? dst_buf : "", nhg_id);
    3537             : 
    3538             :         /* The interface should exist. */
    3539           0 :         ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
    3540           0 :                                         ndm->ndm_ifindex);
    3541           0 :         if (!ifp || !ifp->info)
    3542             :                 return 0;
    3543             : 
    3544             :         /* The interface should be something we're interested in. */
    3545           0 :         if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
    3546             :                 return 0;
    3547             : 
    3548           0 :         zif = (struct zebra_if *)ifp->info;
    3549           0 :         if ((br_if = zif->brslave_info.br_if) == NULL) {
    3550           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    3551           0 :                         zlog_debug(
    3552             :                                 "%s AF_BRIDGE IF %s(%u) brIF %u - no bridge master",
    3553             :                                 nl_msg_type_to_str(h->nlmsg_type), ifp->name,
    3554             :                                 ndm->ndm_ifindex,
    3555             :                                 zif->brslave_info.bridge_ifindex);
    3556           0 :                 return 0;
    3557             :         }
    3558             : 
    3559           0 :         sticky = !!(ndm->ndm_flags & NTF_STICKY);
    3560             : 
    3561           0 :         if (filter_vlan && vid != filter_vlan) {
    3562           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    3563           0 :                         zlog_debug("        Filtered due to filter vlan: %d",
    3564             :                                    filter_vlan);
    3565           0 :                 return 0;
    3566             :         }
    3567             : 
    3568             :         /* If add or update, do accordingly if learnt on a "local" interface; if
    3569             :          * the notification is over VxLAN, this has to be related to
    3570             :          * multi-homing,
    3571             :          * so perform an implicit delete of any local entry (if it exists).
    3572             :          */
    3573           0 :         if (h->nlmsg_type == RTM_NEWNEIGH) {
    3574             :                 /* Drop "permanent" entries. */
    3575           0 :                 if (ndm->ndm_state & NUD_PERMANENT) {
    3576           0 :                         if (IS_ZEBRA_DEBUG_KERNEL)
    3577           0 :                                 zlog_debug(
    3578             :                                         "        Dropping entry because of NUD_PERMANENT");
    3579           0 :                         return 0;
    3580             :                 }
    3581             : 
    3582           0 :                 if (IS_ZEBRA_IF_VXLAN(ifp))
    3583           0 :                         return zebra_vxlan_dp_network_mac_add(
    3584             :                                 ifp, br_if, &mac, vid, nhg_id, sticky,
    3585             :                                 !!(ndm->ndm_flags & NTF_EXT_LEARNED));
    3586             : 
    3587           0 :                 return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
    3588             :                                 sticky, local_inactive, dp_static);
    3589             :         }
    3590             : 
    3591             :         /* This is a delete notification.
    3592             :          * Ignore the notification with IP dest as it may just signify that the
    3593             :          * MAC has moved from remote to local. The exception is the special
    3594             :          * all-zeros MAC that represents the BUM flooding entry; we may have
    3595             :          * to readd it. Otherwise,
    3596             :          *  1. For a MAC over VxLan, check if it needs to be refreshed(readded)
    3597             :          *  2. For a MAC over "local" interface, delete the mac
    3598             :          * Note: We will get notifications from both bridge driver and VxLAN
    3599             :          * driver.
    3600             :          */
    3601           0 :         if (nhg_id)
    3602             :                 return 0;
    3603             : 
    3604           0 :         if (dst_present) {
    3605           0 :                 u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
    3606             : 
    3607           0 :                 if (!memcmp(zero_mac, mac.octet, ETH_ALEN))
    3608           0 :                         return zebra_vxlan_check_readd_vtep(ifp, vtep_ip);
    3609             :                 return 0;
    3610             :         }
    3611             : 
    3612           0 :         if (IS_ZEBRA_IF_VXLAN(ifp))
    3613           0 :                 return zebra_vxlan_dp_network_mac_del(ifp, br_if, &mac, vid);
    3614             : 
    3615           0 :         return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
    3616             : }
    3617             : 
    3618           0 : static int netlink_macfdb_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
    3619             : {
    3620           0 :         int len;
    3621           0 :         struct ndmsg *ndm;
    3622             : 
    3623           0 :         if (h->nlmsg_type != RTM_NEWNEIGH)
    3624             :                 return 0;
    3625             : 
    3626             :         /* Length validity. */
    3627           0 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
    3628           0 :         if (len < 0)
    3629             :                 return -1;
    3630             : 
    3631             :         /* We are interested only in AF_BRIDGE notifications. */
    3632           0 :         ndm = NLMSG_DATA(h);
    3633           0 :         if (ndm->ndm_family != AF_BRIDGE)
    3634             :                 return 0;
    3635             : 
    3636           0 :         return netlink_macfdb_change(h, len, ns_id);
    3637             : }
    3638             : 
    3639             : /* Request for MAC FDB information from the kernel */
    3640           0 : static int netlink_request_macs(struct nlsock *netlink_cmd, int family,
    3641             :                                 int type, ifindex_t master_ifindex)
    3642             : {
    3643           0 :         struct {
    3644             :                 struct nlmsghdr n;
    3645             :                 struct ifinfomsg ifm;
    3646             :                 char buf[256];
    3647             :         } req;
    3648             : 
    3649             :         /* Form the request, specifying filter (rtattr) if needed. */
    3650           0 :         memset(&req, 0, sizeof(req));
    3651           0 :         req.n.nlmsg_type = type;
    3652           0 :         req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
    3653           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    3654           0 :         req.ifm.ifi_family = family;
    3655           0 :         if (master_ifindex)
    3656           0 :                 nl_attr_put32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex);
    3657             : 
    3658           0 :         return netlink_request(netlink_cmd, &req);
    3659             : }
    3660             : 
    3661             : /*
    3662             :  * MAC forwarding database read using netlink interface. This is invoked
    3663             :  * at startup.
    3664             :  */
    3665           0 : int netlink_macfdb_read(struct zebra_ns *zns)
    3666             : {
    3667           0 :         int ret;
    3668           0 :         struct zebra_dplane_info dp_info;
    3669             : 
    3670           0 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    3671             : 
    3672             :         /* Get bridge FDB table. */
    3673           0 :         ret = netlink_request_macs(&zns->netlink_cmd, AF_BRIDGE, RTM_GETNEIGH,
    3674             :                                    0);
    3675           0 :         if (ret < 0)
    3676             :                 return ret;
    3677             :         /* We are reading entire table. */
    3678           0 :         filter_vlan = 0;
    3679           0 :         ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
    3680             :                                  &dp_info, 0, true);
    3681             : 
    3682           0 :         return ret;
    3683             : }
    3684             : 
    3685             : /*
    3686             :  * MAC forwarding database read using netlink interface. This is for a
    3687             :  * specific bridge and matching specific access VLAN (if VLAN-aware bridge).
    3688             :  */
    3689           0 : int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
    3690             :                                    struct interface *br_if)
    3691             : {
    3692           0 :         struct zebra_if *br_zif;
    3693           0 :         struct zebra_if *zif;
    3694           0 :         struct zebra_l2info_vxlan *vxl;
    3695           0 :         struct zebra_dplane_info dp_info;
    3696           0 :         int ret = 0;
    3697             : 
    3698           0 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    3699             : 
    3700             :         /* Save VLAN we're filtering on, if needed. */
    3701           0 :         br_zif = (struct zebra_if *)br_if->info;
    3702           0 :         zif = (struct zebra_if *)ifp->info;
    3703           0 :         vxl = &zif->l2info.vxl;
    3704           0 :         if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
    3705           0 :                 filter_vlan = vxl->access_vlan;
    3706             : 
    3707             :         /* Get bridge FDB table for specific bridge - we do the VLAN filtering.
    3708             :          */
    3709           0 :         ret = netlink_request_macs(&zns->netlink_cmd, AF_BRIDGE, RTM_GETNEIGH,
    3710             :                                    br_if->ifindex);
    3711           0 :         if (ret < 0)
    3712             :                 return ret;
    3713           0 :         ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
    3714             :                                  &dp_info, 0, false);
    3715             : 
    3716             :         /* Reset VLAN filter. */
    3717           0 :         filter_vlan = 0;
    3718           0 :         return ret;
    3719             : }
    3720             : 
    3721             : 
    3722             : /* Request for MAC FDB for a specific MAC address in VLAN from the kernel */
    3723           0 : static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns,
    3724             :                                                   int family, int type,
    3725             :                                                   struct interface *br_if,
    3726             :                                                   const struct ethaddr *mac,
    3727             :                                                   vlanid_t vid)
    3728             : {
    3729           0 :         struct {
    3730             :                 struct nlmsghdr n;
    3731             :                 struct ndmsg ndm;
    3732             :                 char buf[256];
    3733             :         } req;
    3734           0 :         struct zebra_if *br_zif;
    3735             : 
    3736           0 :         memset(&req, 0, sizeof(req));
    3737           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
    3738           0 :         req.n.nlmsg_type = type;        /* RTM_GETNEIGH */
    3739           0 :         req.n.nlmsg_flags = NLM_F_REQUEST;
    3740           0 :         req.ndm.ndm_family = family;    /* AF_BRIDGE */
    3741             :         /* req.ndm.ndm_state = NUD_REACHABLE; */
    3742             : 
    3743           0 :         nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
    3744             : 
    3745           0 :         br_zif = (struct zebra_if *)br_if->info;
    3746           0 :         if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0)
    3747           0 :                 nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid);
    3748             : 
    3749           0 :         nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex);
    3750             : 
    3751           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    3752           0 :                 zlog_debug(
    3753             :                         "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u",
    3754             :                         __func__, nl_family_to_str(req.ndm.ndm_family),
    3755             :                         br_if->name, br_if->ifindex, br_if->vrf->name,
    3756             :                         br_if->vrf->vrf_id, mac, vid);
    3757             : 
    3758           0 :         return netlink_request(&zns->netlink_cmd, &req);
    3759             : }
    3760             : 
    3761           0 : int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
    3762             :                                      struct interface *br_if,
    3763             :                                      const struct ethaddr *mac, vlanid_t vid)
    3764             : {
    3765           0 :         int ret = 0;
    3766           0 :         struct zebra_dplane_info dp_info;
    3767             : 
    3768           0 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    3769             : 
    3770             :         /* Get bridge FDB table for specific bridge - we do the VLAN filtering.
    3771             :          */
    3772           0 :         ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE,
    3773             :                                                      RTM_GETNEIGH,
    3774             :                                                      br_if, mac, vid);
    3775           0 :         if (ret < 0)
    3776             :                 return ret;
    3777             : 
    3778           0 :         ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
    3779             :                                  &dp_info, 1, false);
    3780             : 
    3781           0 :         return ret;
    3782             : }
    3783             : 
    3784             : /*
    3785             :  * Netlink-specific handler for MAC updates using dataplane context object.
    3786             :  */
    3787           0 : ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
    3788             :                                   size_t datalen)
    3789             : {
    3790           0 :         struct ipaddr vtep_ip;
    3791           0 :         vlanid_t vid;
    3792           0 :         ssize_t total;
    3793           0 :         int cmd;
    3794           0 :         uint8_t flags;
    3795           0 :         uint16_t state;
    3796           0 :         uint32_t nhg_id;
    3797           0 :         uint32_t update_flags;
    3798           0 :         bool nfy = false;
    3799           0 :         uint8_t nfy_flags = 0;
    3800           0 :         int proto = RTPROT_ZEBRA;
    3801             : 
    3802           0 :         if (dplane_ctx_get_type(ctx) != 0)
    3803           0 :                 proto = zebra2proto(dplane_ctx_get_type(ctx));
    3804             : 
    3805           0 :         cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
    3806           0 :                           ? RTM_NEWNEIGH : RTM_DELNEIGH;
    3807             : 
    3808           0 :         flags = NTF_MASTER;
    3809           0 :         state = NUD_REACHABLE;
    3810             : 
    3811           0 :         update_flags = dplane_ctx_mac_get_update_flags(ctx);
    3812           0 :         if (update_flags & DPLANE_MAC_REMOTE) {
    3813           0 :                 flags |= NTF_SELF;
    3814           0 :                 if (dplane_ctx_mac_is_sticky(ctx)) {
    3815             :                         /* NUD_NOARP prevents the entry from expiring */
    3816             :                         state |= NUD_NOARP;
    3817             :                         /* sticky the entry from moving */
    3818             :                         flags |= NTF_STICKY;
    3819             :                 } else {
    3820           0 :                         flags |= NTF_EXT_LEARNED;
    3821             :                 }
    3822             :                 /* if it was static-local previously we need to clear the
    3823             :                  * notify flags on replace with remote
    3824             :                  */
    3825           0 :                 if (update_flags & DPLANE_MAC_WAS_STATIC)
    3826           0 :                         nfy = true;
    3827             :         } else {
    3828             :                 /* local mac */
    3829           0 :                 if (update_flags & DPLANE_MAC_SET_STATIC) {
    3830           0 :                         nfy_flags |= FDB_NOTIFY_BIT;
    3831           0 :                         state |= NUD_NOARP;
    3832             :                 }
    3833             : 
    3834           0 :                 if (update_flags & DPLANE_MAC_SET_INACTIVE)
    3835           0 :                         nfy_flags |= FDB_NOTIFY_INACTIVE_BIT;
    3836             : 
    3837             :                 nfy = true;
    3838             :         }
    3839             : 
    3840           0 :         nhg_id = dplane_ctx_mac_get_nhg_id(ctx);
    3841           0 :         vtep_ip.ipaddr_v4 = *(dplane_ctx_mac_get_vtep_ip(ctx));
    3842           0 :         SET_IPADDR_V4(&vtep_ip);
    3843             : 
    3844           0 :         if (IS_ZEBRA_DEBUG_KERNEL) {
    3845           0 :                 char vid_buf[20];
    3846           0 :                 const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx);
    3847             : 
    3848           0 :                 vid = dplane_ctx_mac_get_vlan(ctx);
    3849           0 :                 if (vid > 0)
    3850           0 :                         snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid);
    3851             :                 else
    3852           0 :                         vid_buf[0] = '\0';
    3853             : 
    3854           0 :                 zlog_debug(
    3855             :                         "Tx %s family %s IF %s(%u)%s %sMAC %pEA dst %pIA nhg %u%s%s%s%s%s",
    3856             :                         nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE),
    3857             :                         dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
    3858             :                         vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
    3859             :                         mac, &vtep_ip, nhg_id,
    3860             :                         (update_flags & DPLANE_MAC_REMOTE) ? " rem" : "",
    3861             :                         (update_flags & DPLANE_MAC_WAS_STATIC) ? " clr_sync"
    3862             :                                                                : "",
    3863             :                         (update_flags & DPLANE_MAC_SET_STATIC) ? " static" : "",
    3864             :                         (update_flags & DPLANE_MAC_SET_INACTIVE) ? " inactive"
    3865             :                                                                  : "",
    3866             :                         nfy ? " nfy" : "");
    3867             :         }
    3868             : 
    3869           0 :         total = netlink_neigh_update_msg_encode(
    3870           0 :                 ctx, cmd, (const void *)dplane_ctx_mac_get_addr(ctx), ETH_ALEN,
    3871             :                 &vtep_ip, true, AF_BRIDGE, 0, flags, state, nhg_id, nfy,
    3872             :                 nfy_flags, false /*ext*/, 0 /*ext_flags*/, data, datalen,
    3873             :                 proto);
    3874             : 
    3875           0 :         return total;
    3876             : }
    3877             : 
    3878             : /*
    3879             :  * In the event the kernel deletes ipv4 link-local neighbor entries created for
    3880             :  * 5549 support, re-install them.
    3881             :  */
    3882           0 : static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif,
    3883             :                                 struct interface *ifp, struct ipaddr *ip,
    3884             :                                 bool handle_failed)
    3885             : {
    3886           0 :         if (ndm->ndm_family != AF_INET)
    3887             :                 return;
    3888             : 
    3889           0 :         if (!zif->v6_2_v4_ll_neigh_entry)
    3890             :                 return;
    3891             : 
    3892           0 :         if (ipv4_ll.s_addr != ip->ip._v4_addr.s_addr)
    3893             :                 return;
    3894             : 
    3895           0 :         if (handle_failed && ndm->ndm_state & NUD_FAILED) {
    3896           0 :                 zlog_info("Neighbor Entry for %s has entered a failed state, not reinstalling",
    3897             :                           ifp->name);
    3898           0 :                 return;
    3899             :         }
    3900             : 
    3901           0 :         if_nbr_ipv6ll_to_ipv4ll_neigh_update(ifp, &zif->v6_2_v4_ll_addr6, true);
    3902             : }
    3903             : 
    3904             : #define NUD_VALID                                                              \
    3905             :         (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE     \
    3906             :          | NUD_DELAY)
    3907             : #define NUD_LOCAL_ACTIVE                                                 \
    3908             :         (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)
    3909             : 
    3910             : static int netlink_nbr_entry_state_to_zclient(int nbr_state)
    3911             : {
    3912             :         /* an exact match is done between
    3913             :          * - netlink neighbor state values: NDM_XXX (see in linux/neighbour.h)
    3914             :          * - zclient neighbor state values: ZEBRA_NEIGH_STATE_XXX
    3915             :          *  (see in lib/zclient.h)
    3916             :          */
    3917             :         return nbr_state;
    3918             : }
    3919           6 : static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
    3920             : {
    3921           6 :         struct ndmsg *ndm;
    3922           6 :         struct interface *ifp;
    3923           6 :         struct zebra_if *zif;
    3924           6 :         struct rtattr *tb[NDA_MAX + 1];
    3925           6 :         struct interface *link_if;
    3926           6 :         struct ethaddr mac;
    3927           6 :         struct ipaddr ip;
    3928           6 :         char buf[ETHER_ADDR_STRLEN];
    3929           6 :         int mac_present = 0;
    3930           6 :         bool is_ext;
    3931           6 :         bool is_router;
    3932           6 :         bool local_inactive;
    3933           6 :         uint32_t ext_flags = 0;
    3934           6 :         bool dp_static = false;
    3935           6 :         int l2_len = 0;
    3936           6 :         int cmd;
    3937             : 
    3938           6 :         ndm = NLMSG_DATA(h);
    3939             : 
    3940             :         /* The interface should exist. */
    3941           6 :         ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
    3942           6 :                                         ndm->ndm_ifindex);
    3943           6 :         if (!ifp || !ifp->info)
    3944             :                 return 0;
    3945             : 
    3946           6 :         zif = (struct zebra_if *)ifp->info;
    3947             : 
    3948             :         /* Parse attributes and extract fields of interest. */
    3949           6 :         netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
    3950             : 
    3951           6 :         if (!tb[NDA_DST]) {
    3952           0 :                 zlog_debug("%s family %s IF %s(%u) vrf %s(%u) - no DST",
    3953             :                            nl_msg_type_to_str(h->nlmsg_type),
    3954             :                            nl_family_to_str(ndm->ndm_family), ifp->name,
    3955             :                            ndm->ndm_ifindex, ifp->vrf->name, ifp->vrf->vrf_id);
    3956           0 :                 return 0;
    3957             :         }
    3958             : 
    3959           6 :         memset(&ip, 0, sizeof(ip));
    3960           6 :         ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6;
    3961           6 :         memcpy(&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
    3962             : 
    3963             :         /* if kernel deletes our rfc5549 neighbor entry, re-install it */
    3964           6 :         if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) {
    3965           0 :                 netlink_handle_5549(ndm, zif, ifp, &ip, false);
    3966           0 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    3967           0 :                         zlog_debug(
    3968             :                                 "    Neighbor Entry Received is a 5549 entry, finished");
    3969           0 :                 return 0;
    3970             :         }
    3971             : 
    3972             :         /* if kernel marks our rfc5549 neighbor entry invalid, re-install it */
    3973           6 :         if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID))
    3974           0 :                 netlink_handle_5549(ndm, zif, ifp, &ip, true);
    3975             : 
    3976             :         /* we send link layer information to client:
    3977             :          * - nlmsg_type = RTM_DELNEIGH|NEWNEIGH|GETNEIGH
    3978             :          * - struct ipaddr ( for DEL and GET)
    3979             :          * - struct ethaddr mac; (for NEW)
    3980             :          */
    3981           6 :         if (h->nlmsg_type == RTM_NEWNEIGH)
    3982             :                 cmd = ZEBRA_NHRP_NEIGH_ADDED;
    3983           0 :         else if (h->nlmsg_type == RTM_GETNEIGH)
    3984             :                 cmd = ZEBRA_NHRP_NEIGH_GET;
    3985           0 :         else if (h->nlmsg_type == RTM_DELNEIGH)
    3986             :                 cmd = ZEBRA_NHRP_NEIGH_REMOVED;
    3987             :         else {
    3988           0 :                 zlog_debug("%s(): unknown nlmsg type %u", __func__,
    3989             :                            h->nlmsg_type);
    3990           0 :                 return 0;
    3991             :         }
    3992           6 :         if (tb[NDA_LLADDR]) {
    3993             :                 /* copy LLADDR information */
    3994           6 :                 l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
    3995             :         }
    3996           6 :         if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) {
    3997           0 :                 union sockunion link_layer_ipv4;
    3998             : 
    3999           0 :                 if (l2_len) {
    4000           0 :                         sockunion_family(&link_layer_ipv4) = AF_INET;
    4001           0 :                         memcpy((void *)sockunion_get_addr(&link_layer_ipv4),
    4002             :                                RTA_DATA(tb[NDA_LLADDR]), l2_len);
    4003             :                 } else
    4004           0 :                         sockunion_family(&link_layer_ipv4) = AF_UNSPEC;
    4005           0 :                 zsend_nhrp_neighbor_notify(
    4006             :                         cmd, ifp, &ip,
    4007           0 :                         netlink_nbr_entry_state_to_zclient(ndm->ndm_state),
    4008             :                         &link_layer_ipv4);
    4009             :         }
    4010             : 
    4011           6 :         if (h->nlmsg_type == RTM_GETNEIGH)
    4012             :                 return 0;
    4013             : 
    4014             :         /* The neighbor is present on an SVI. From this, we locate the
    4015             :          * underlying
    4016             :          * bridge because we're only interested in neighbors on a VxLAN bridge.
    4017             :          * The bridge is located based on the nature of the SVI:
    4018             :          * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN
    4019             :          * interface
    4020             :          * and is linked to the bridge
    4021             :          * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge
    4022             :          * interface
    4023             :          * itself
    4024             :          */
    4025           6 :         if (IS_ZEBRA_IF_VLAN(ifp)) {
    4026           0 :                 link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
    4027           0 :                                                     zif->link_ifindex);
    4028           0 :                 if (!link_if)
    4029             :                         return 0;
    4030           6 :         } else if (IS_ZEBRA_IF_BRIDGE(ifp))
    4031             :                 link_if = ifp;
    4032             :         else {
    4033           6 :                 link_if = NULL;
    4034           6 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    4035           0 :                         zlog_debug(
    4036             :                                 "    Neighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
    4037             :         }
    4038             : 
    4039           6 :         memset(&mac, 0, sizeof(mac));
    4040           6 :         if (h->nlmsg_type == RTM_NEWNEIGH) {
    4041           6 :                 if (tb[NDA_LLADDR]) {
    4042           6 :                         if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
    4043           0 :                                 if (IS_ZEBRA_DEBUG_KERNEL)
    4044           0 :                                         zlog_debug(
    4045             :                                                 "%s family %s IF %s(%u) vrf %s(%u) - LLADDR is not MAC, len %lu",
    4046             :                                                 nl_msg_type_to_str(
    4047             :                                                         h->nlmsg_type),
    4048             :                                                 nl_family_to_str(
    4049             :                                                         ndm->ndm_family),
    4050             :                                                 ifp->name, ndm->ndm_ifindex,
    4051             :                                                 ifp->vrf->name,
    4052             :                                                 ifp->vrf->vrf_id,
    4053             :                                                 (unsigned long)RTA_PAYLOAD(
    4054             :                                                         tb[NDA_LLADDR]));
    4055           0 :                                 return 0;
    4056             :                         }
    4057             : 
    4058           6 :                         mac_present = 1;
    4059           6 :                         memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN);
    4060             :                 }
    4061             : 
    4062           6 :                 is_ext = !!(ndm->ndm_flags & NTF_EXT_LEARNED);
    4063           6 :                 is_router = !!(ndm->ndm_flags & NTF_ROUTER);
    4064             : 
    4065           6 :                 if (tb[NDA_EXT_FLAGS]) {
    4066           0 :                         ext_flags = *(uint32_t *)RTA_DATA(tb[NDA_EXT_FLAGS]);
    4067           0 :                         if (ext_flags & NTF_E_MH_PEER_SYNC)
    4068           0 :                                 dp_static = true;
    4069             :                 }
    4070             : 
    4071           6 :                 if (IS_ZEBRA_DEBUG_KERNEL)
    4072           0 :                         zlog_debug(
    4073             :                                 "Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA MAC %s state 0x%x flags 0x%x ext_flags 0x%x",
    4074             :                                 nl_msg_type_to_str(h->nlmsg_type),
    4075             :                                 nl_family_to_str(ndm->ndm_family), ifp->name,
    4076             :                                 ndm->ndm_ifindex, ifp->vrf->name,
    4077             :                                 ifp->vrf->vrf_id, &ip,
    4078             :                                 mac_present
    4079             :                                         ? prefix_mac2str(&mac, buf, sizeof(buf))
    4080             :                                         : "",
    4081             :                                 ndm->ndm_state, ndm->ndm_flags, ext_flags);
    4082             : 
    4083             :                 /* If the neighbor state is valid for use, process as an add or
    4084             :                  * update
    4085             :                  * else process as a delete. Note that the delete handling may
    4086             :                  * result
    4087             :                  * in re-adding the neighbor if it is a valid "remote" neighbor.
    4088             :                  */
    4089           6 :                 if (ndm->ndm_state & NUD_VALID) {
    4090           6 :                         if (zebra_evpn_mh_do_adv_reachable_neigh_only())
    4091           0 :                                 local_inactive =
    4092             :                                         !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
    4093             :                         else
    4094             :                                 /* If EVPN-MH is not enabled we treat STALE
    4095             :                                  * neighbors as locally-active and advertise
    4096             :                                  * them
    4097             :                                  */
    4098             :                                 local_inactive = false;
    4099             : 
    4100             :                         /* Add local neighbors to the l3 interface database */
    4101           6 :                         if (is_ext)
    4102           0 :                                 zebra_neigh_del(ifp, &ip);
    4103             :                         else
    4104           6 :                                 zebra_neigh_add(ifp, &ip, &mac);
    4105             : 
    4106           6 :                         if (link_if)
    4107           0 :                                 zebra_vxlan_handle_kernel_neigh_update(
    4108           0 :                                         ifp, link_if, &ip, &mac, ndm->ndm_state,
    4109             :                                         is_ext, is_router, local_inactive,
    4110             :                                         dp_static);
    4111           6 :                         return 0;
    4112             :                 }
    4113             : 
    4114             : 
    4115           0 :                 zebra_neigh_del(ifp, &ip);
    4116           0 :                 if (link_if)
    4117           0 :                         zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
    4118           0 :                 return 0;
    4119             :         }
    4120             : 
    4121           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    4122           0 :                 zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA",
    4123             :                            nl_msg_type_to_str(h->nlmsg_type),
    4124             :                            nl_family_to_str(ndm->ndm_family), ifp->name,
    4125             :                            ndm->ndm_ifindex, ifp->vrf->name, ifp->vrf->vrf_id,
    4126             :                            &ip);
    4127             : 
    4128             :         /* Process the delete - it may result in re-adding the neighbor if it is
    4129             :          * a valid "remote" neighbor.
    4130             :          */
    4131           0 :         zebra_neigh_del(ifp, &ip);
    4132           0 :         if (link_if)
    4133           0 :                 zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
    4134             : 
    4135             :         return 0;
    4136             : }
    4137             : 
    4138           0 : static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
    4139             : {
    4140           0 :         int len;
    4141           0 :         struct ndmsg *ndm;
    4142             : 
    4143           0 :         if (h->nlmsg_type != RTM_NEWNEIGH)
    4144             :                 return 0;
    4145             : 
    4146             :         /* Length validity. */
    4147           0 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
    4148           0 :         if (len < 0)
    4149             :                 return -1;
    4150             : 
    4151             :         /* We are interested only in AF_INET or AF_INET6 notifications. */
    4152           0 :         ndm = NLMSG_DATA(h);
    4153           0 :         if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6)
    4154             :                 return 0;
    4155             : 
    4156           0 :         return netlink_neigh_change(h, len);
    4157             : }
    4158             : 
    4159             : /* Request for IP neighbor information from the kernel */
    4160           0 : static int netlink_request_neigh(struct nlsock *netlink_cmd, int family,
    4161             :                                  int type, ifindex_t ifindex)
    4162             : {
    4163           0 :         struct {
    4164             :                 struct nlmsghdr n;
    4165             :                 struct ndmsg ndm;
    4166             :                 char buf[256];
    4167             :         } req;
    4168             : 
    4169             :         /* Form the request, specifying filter (rtattr) if needed. */
    4170           0 :         memset(&req, 0, sizeof(req));
    4171           0 :         req.n.nlmsg_type = type;
    4172           0 :         req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
    4173           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
    4174           0 :         req.ndm.ndm_family = family;
    4175           0 :         if (ifindex)
    4176           0 :                 nl_attr_put32(&req.n, sizeof(req), NDA_IFINDEX, ifindex);
    4177             : 
    4178           0 :         return netlink_request(netlink_cmd, &req);
    4179             : }
    4180             : 
    4181             : /*
    4182             :  * IP Neighbor table read using netlink interface. This is invoked
    4183             :  * at startup.
    4184             :  */
    4185           0 : int netlink_neigh_read(struct zebra_ns *zns)
    4186             : {
    4187           0 :         int ret;
    4188           0 :         struct zebra_dplane_info dp_info;
    4189             : 
    4190           0 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    4191             : 
    4192             :         /* Get IP neighbor table. */
    4193           0 :         ret = netlink_request_neigh(&zns->netlink_cmd, AF_UNSPEC, RTM_GETNEIGH,
    4194             :                                     0);
    4195           0 :         if (ret < 0)
    4196             :                 return ret;
    4197           0 :         ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
    4198             :                                  &dp_info, 0, true);
    4199             : 
    4200           0 :         return ret;
    4201             : }
    4202             : 
    4203             : /*
    4204             :  * IP Neighbor table read using netlink interface. This is for a specific
    4205             :  * VLAN device.
    4206             :  */
    4207           0 : int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
    4208             : {
    4209           0 :         int ret = 0;
    4210           0 :         struct zebra_dplane_info dp_info;
    4211             : 
    4212           0 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    4213             : 
    4214           0 :         ret = netlink_request_neigh(&zns->netlink_cmd, AF_UNSPEC, RTM_GETNEIGH,
    4215             :                                     vlan_if->ifindex);
    4216           0 :         if (ret < 0)
    4217             :                 return ret;
    4218           0 :         ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
    4219             :                                  &dp_info, 0, false);
    4220             : 
    4221           0 :         return ret;
    4222             : }
    4223             : 
    4224             : /*
    4225             :  * Request for a specific IP in VLAN (SVI) device from IP Neighbor table,
    4226             :  * read using netlink interface.
    4227             :  */
    4228           0 : static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns,
    4229             :                                                   int type,
    4230             :                                                   const struct ipaddr *ip,
    4231             :                                                   ifindex_t ifindex)
    4232             : {
    4233           0 :         struct {
    4234             :                 struct nlmsghdr n;
    4235             :                 struct ndmsg ndm;
    4236             :                 char buf[256];
    4237             :         } req;
    4238           0 :         int ipa_len;
    4239             : 
    4240             :         /* Form the request, specifying filter (rtattr) if needed. */
    4241           0 :         memset(&req, 0, sizeof(req));
    4242           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
    4243           0 :         req.n.nlmsg_flags = NLM_F_REQUEST;
    4244           0 :         req.n.nlmsg_type = type; /* RTM_GETNEIGH */
    4245           0 :         req.ndm.ndm_ifindex = ifindex;
    4246             : 
    4247           0 :         if (IS_IPADDR_V4(ip)) {
    4248           0 :                 ipa_len = IPV4_MAX_BYTELEN;
    4249           0 :                 req.ndm.ndm_family = AF_INET;
    4250             : 
    4251             :         } else {
    4252           0 :                 ipa_len = IPV6_MAX_BYTELEN;
    4253           0 :                 req.ndm.ndm_family = AF_INET6;
    4254             :         }
    4255             : 
    4256           0 :         nl_attr_put(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len);
    4257             : 
    4258           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    4259           0 :                 zlog_debug("%s: Tx %s family %s IF %u IP %pIA flags 0x%x",
    4260             :                            __func__, nl_msg_type_to_str(type),
    4261             :                            nl_family_to_str(req.ndm.ndm_family), ifindex, ip,
    4262             :                            req.n.nlmsg_flags);
    4263             : 
    4264           0 :         return netlink_request(&zns->netlink_cmd, &req);
    4265             : }
    4266             : 
    4267           0 : int netlink_neigh_read_specific_ip(const struct ipaddr *ip,
    4268             :                                    struct interface *vlan_if)
    4269             : {
    4270           0 :         int ret = 0;
    4271           0 :         struct zebra_ns *zns;
    4272           0 :         struct zebra_vrf *zvrf = vlan_if->vrf->info;
    4273           0 :         struct zebra_dplane_info dp_info;
    4274             : 
    4275           0 :         zns = zvrf->zns;
    4276             : 
    4277           0 :         zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
    4278             : 
    4279           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    4280           0 :                 zlog_debug("%s: neigh request IF %s(%u) IP %pIA vrf %s(%u)",
    4281             :                            __func__, vlan_if->name, vlan_if->ifindex, ip,
    4282             :                            vlan_if->vrf->name, vlan_if->vrf->vrf_id);
    4283             : 
    4284           0 :         ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip,
    4285             :                                             vlan_if->ifindex);
    4286           0 :         if (ret < 0)
    4287             :                 return ret;
    4288             : 
    4289           0 :         ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
    4290             :                                  &dp_info, 1, false);
    4291             : 
    4292           0 :         return ret;
    4293             : }
    4294             : 
    4295          11 : int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
    4296             : {
    4297          11 :         int len;
    4298          11 :         struct ndmsg *ndm;
    4299             : 
    4300          11 :         if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH
    4301             :               || h->nlmsg_type == RTM_GETNEIGH))
    4302             :                 return 0;
    4303             : 
    4304             :         /* Length validity. */
    4305          11 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
    4306          11 :         if (len < 0) {
    4307           0 :                 zlog_err(
    4308             :                         "%s: Message received from netlink is of a broken size %d %zu",
    4309             :                         __func__, h->nlmsg_len,
    4310             :                         (size_t)NLMSG_LENGTH(sizeof(struct ndmsg)));
    4311           0 :                 return -1;
    4312             :         }
    4313             : 
    4314             :         /* Is this a notification for the MAC FDB or IP neighbor table? */
    4315          11 :         ndm = NLMSG_DATA(h);
    4316          11 :         if (ndm->ndm_family == AF_BRIDGE)
    4317           0 :                 return netlink_macfdb_change(h, len, ns_id);
    4318             : 
    4319          11 :         if (ndm->ndm_type != RTN_UNICAST)
    4320             :                 return 0;
    4321             : 
    4322           6 :         if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6)
    4323           6 :                 return netlink_ipneigh_change(h, len, ns_id);
    4324             :         else {
    4325           0 :                 flog_warn(
    4326             :                         EC_ZEBRA_UNKNOWN_FAMILY,
    4327             :                         "Invalid address family: %u received from kernel neighbor change: %s",
    4328             :                         ndm->ndm_family, nl_msg_type_to_str(h->nlmsg_type));
    4329           0 :                 return 0;
    4330             :         }
    4331             : 
    4332             :         return 0;
    4333             : }
    4334             : 
    4335             : /*
    4336             :  * Utility neighbor-update function, using info from dplane context.
    4337             :  */
    4338           0 : static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
    4339             :                                         int cmd, void *buf, size_t buflen)
    4340             : {
    4341           0 :         const struct ipaddr *ip;
    4342           0 :         const struct ethaddr *mac = NULL;
    4343           0 :         const struct ipaddr *link_ip = NULL;
    4344           0 :         const void *link_ptr = NULL;
    4345           0 :         char buf2[ETHER_ADDR_STRLEN];
    4346             : 
    4347           0 :         int llalen;
    4348           0 :         uint8_t flags;
    4349           0 :         uint16_t state;
    4350           0 :         uint8_t family;
    4351           0 :         uint32_t update_flags;
    4352           0 :         uint32_t ext_flags = 0;
    4353           0 :         bool ext = false;
    4354           0 :         int proto = RTPROT_ZEBRA;
    4355             : 
    4356           0 :         if (dplane_ctx_get_type(ctx) != 0)
    4357           0 :                 proto = zebra2proto(dplane_ctx_get_type(ctx));
    4358             : 
    4359           0 :         ip = dplane_ctx_neigh_get_ipaddr(ctx);
    4360             : 
    4361           0 :         if (dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_INSTALL
    4362           0 :             || dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_DELETE) {
    4363           0 :                 link_ip = dplane_ctx_neigh_get_link_ip(ctx);
    4364           0 :                 llalen = IPADDRSZ(link_ip);
    4365           0 :                 link_ptr = (const void *)&(link_ip->ip.addr);
    4366           0 :                 ipaddr2str(link_ip, buf2, sizeof(buf2));
    4367             :         } else {
    4368           0 :                 mac = dplane_ctx_neigh_get_mac(ctx);
    4369           0 :                 llalen = ETH_ALEN;
    4370           0 :                 link_ptr = (const void *)mac;
    4371           0 :                 if (is_zero_mac(mac))
    4372             :                         mac = NULL;
    4373           0 :                 if (mac)
    4374           0 :                         prefix_mac2str(mac, buf2, sizeof(buf2));
    4375             :                 else
    4376           0 :                         snprintf(buf2, sizeof(buf2), "null");
    4377             :         }
    4378           0 :         update_flags = dplane_ctx_neigh_get_update_flags(ctx);
    4379           0 :         flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
    4380           0 :         state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
    4381             : 
    4382           0 :         family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
    4383             : 
    4384           0 :         if (update_flags & DPLANE_NEIGH_REMOTE) {
    4385           0 :                 flags |= NTF_EXT_LEARNED;
    4386             :                 /* if it was static-local previously we need to clear the
    4387             :                  * ext flags on replace with remote
    4388             :                  */
    4389           0 :                 if (update_flags & DPLANE_NEIGH_WAS_STATIC)
    4390           0 :                         ext = true;
    4391           0 :         } else if (!(update_flags & DPLANE_NEIGH_NO_EXTENSION)) {
    4392           0 :                 ext = true;
    4393             :                 /* local neigh */
    4394           0 :                 if (update_flags & DPLANE_NEIGH_SET_STATIC)
    4395           0 :                         ext_flags |= NTF_E_MH_PEER_SYNC;
    4396             :         }
    4397           0 :         if (IS_ZEBRA_DEBUG_KERNEL)
    4398           0 :                 zlog_debug(
    4399             :                         "Tx %s family %s IF %s(%u) Neigh %pIA %s %s flags 0x%x state 0x%x %sext_flags 0x%x",
    4400             :                         nl_msg_type_to_str(cmd), nl_family_to_str(family),
    4401             :                         dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
    4402             :                         ip, link_ip ? "Link" : "MAC", buf2, flags, state,
    4403             :                         ext ? "ext " : "", ext_flags);
    4404             : 
    4405           0 :         return netlink_neigh_update_msg_encode(
    4406             :                 ctx, cmd, link_ptr, llalen, ip, true, family, RTN_UNICAST,
    4407             :                 flags, state, 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext,
    4408             :                 ext_flags, buf, buflen, proto);
    4409             : }
    4410             : 
    4411           0 : static int netlink_neigh_table_update_ctx(const struct zebra_dplane_ctx *ctx,
    4412             :                                           void *data, size_t datalen)
    4413             : {
    4414           0 :         struct {
    4415             :                 struct nlmsghdr n;
    4416             :                 struct ndtmsg ndtm;
    4417             :                 char buf[];
    4418           0 :         } *req = data;
    4419           0 :         struct rtattr *nest;
    4420           0 :         uint8_t family;
    4421           0 :         ifindex_t idx;
    4422           0 :         uint32_t val;
    4423             : 
    4424           0 :         if (datalen < sizeof(*req))
    4425             :                 return 0;
    4426           0 :         memset(req, 0, sizeof(*req));
    4427           0 :         family = dplane_ctx_neightable_get_family(ctx);
    4428           0 :         idx = dplane_ctx_get_ifindex(ctx);
    4429             : 
    4430           0 :         req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
    4431           0 :         req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE;
    4432           0 :         req->n.nlmsg_type = RTM_SETNEIGHTBL;
    4433           0 :         req->ndtm.ndtm_family = family;
    4434             : 
    4435           0 :         nl_attr_put(&req->n, datalen, NDTA_NAME,
    4436             :                     family == AF_INET ? "arp_cache" : "ndisc_cache", 10);
    4437           0 :         nest = nl_attr_nest(&req->n, datalen, NDTA_PARMS);
    4438           0 :         if (nest == NULL)
    4439             :                 return 0;
    4440           0 :         if (!nl_attr_put(&req->n, datalen, NDTPA_IFINDEX, &idx, sizeof(idx)))
    4441             :                 return 0;
    4442           0 :         val = dplane_ctx_neightable_get_app_probes(ctx);
    4443           0 :         if (!nl_attr_put(&req->n, datalen, NDTPA_APP_PROBES, &val, sizeof(val)))
    4444             :                 return 0;
    4445           0 :         val = dplane_ctx_neightable_get_mcast_probes(ctx);
    4446           0 :         if (!nl_attr_put(&req->n, datalen, NDTPA_MCAST_PROBES, &val,
    4447             :                          sizeof(val)))
    4448             :                 return 0;
    4449           0 :         val = dplane_ctx_neightable_get_ucast_probes(ctx);
    4450           0 :         if (!nl_attr_put(&req->n, datalen, NDTPA_UCAST_PROBES, &val,
    4451             :                          sizeof(val)))
    4452             :                 return 0;
    4453           0 :         nl_attr_nest_end(&req->n, nest);
    4454             : 
    4455           0 :         return NLMSG_ALIGN(req->n.nlmsg_len);
    4456             : }
    4457             : 
    4458           0 : static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
    4459             :                                          void *buf, size_t buflen)
    4460             : {
    4461           0 :         ssize_t ret = 0;
    4462             : 
    4463           0 :         switch (dplane_ctx_get_op(ctx)) {
    4464           0 :         case DPLANE_OP_NEIGH_INSTALL:
    4465             :         case DPLANE_OP_NEIGH_UPDATE:
    4466             :         case DPLANE_OP_NEIGH_DISCOVER:
    4467             :         case DPLANE_OP_NEIGH_IP_INSTALL:
    4468           0 :                 ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
    4469           0 :                 break;
    4470           0 :         case DPLANE_OP_NEIGH_DELETE:
    4471             :         case DPLANE_OP_NEIGH_IP_DELETE:
    4472           0 :                 ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen);
    4473           0 :                 break;
    4474           0 :         case DPLANE_OP_VTEP_ADD:
    4475           0 :                 ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf,
    4476             :                                                      buflen);
    4477           0 :                 break;
    4478           0 :         case DPLANE_OP_VTEP_DELETE:
    4479           0 :                 ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf,
    4480             :                                                      buflen);
    4481           0 :                 break;
    4482           0 :         case DPLANE_OP_NEIGH_TABLE_UPDATE:
    4483           0 :                 ret = netlink_neigh_table_update_ctx(ctx, buf, buflen);
    4484           0 :                 break;
    4485           0 :         case DPLANE_OP_ROUTE_INSTALL:
    4486             :         case DPLANE_OP_ROUTE_UPDATE:
    4487             :         case DPLANE_OP_ROUTE_DELETE:
    4488             :         case DPLANE_OP_ROUTE_NOTIFY:
    4489             :         case DPLANE_OP_NH_INSTALL:
    4490             :         case DPLANE_OP_NH_UPDATE:
    4491             :         case DPLANE_OP_NH_DELETE:
    4492             :         case DPLANE_OP_LSP_INSTALL:
    4493             :         case DPLANE_OP_LSP_UPDATE:
    4494             :         case DPLANE_OP_LSP_DELETE:
    4495             :         case DPLANE_OP_LSP_NOTIFY:
    4496             :         case DPLANE_OP_PW_INSTALL:
    4497             :         case DPLANE_OP_PW_UNINSTALL:
    4498             :         case DPLANE_OP_SYS_ROUTE_ADD:
    4499             :         case DPLANE_OP_SYS_ROUTE_DELETE:
    4500             :         case DPLANE_OP_ADDR_INSTALL:
    4501             :         case DPLANE_OP_ADDR_UNINSTALL:
    4502             :         case DPLANE_OP_MAC_INSTALL:
    4503             :         case DPLANE_OP_MAC_DELETE:
    4504             :         case DPLANE_OP_RULE_ADD:
    4505             :         case DPLANE_OP_RULE_DELETE:
    4506             :         case DPLANE_OP_RULE_UPDATE:
    4507             :         case DPLANE_OP_BR_PORT_UPDATE:
    4508             :         case DPLANE_OP_IPTABLE_ADD:
    4509             :         case DPLANE_OP_IPTABLE_DELETE:
    4510             :         case DPLANE_OP_IPSET_ADD:
    4511             :         case DPLANE_OP_IPSET_DELETE:
    4512             :         case DPLANE_OP_IPSET_ENTRY_ADD:
    4513             :         case DPLANE_OP_IPSET_ENTRY_DELETE:
    4514             :         case DPLANE_OP_GRE_SET:
    4515             :         case DPLANE_OP_INTF_ADDR_ADD:
    4516             :         case DPLANE_OP_INTF_ADDR_DEL:
    4517             :         case DPLANE_OP_INTF_NETCONFIG:
    4518             :         case DPLANE_OP_INTF_INSTALL:
    4519             :         case DPLANE_OP_INTF_UPDATE:
    4520             :         case DPLANE_OP_INTF_DELETE:
    4521             :         case DPLANE_OP_TC_QDISC_INSTALL:
    4522             :         case DPLANE_OP_TC_QDISC_UNINSTALL:
    4523             :         case DPLANE_OP_TC_CLASS_ADD:
    4524             :         case DPLANE_OP_TC_CLASS_DELETE:
    4525             :         case DPLANE_OP_TC_CLASS_UPDATE:
    4526             :         case DPLANE_OP_TC_FILTER_ADD:
    4527             :         case DPLANE_OP_TC_FILTER_DELETE:
    4528             :         case DPLANE_OP_TC_FILTER_UPDATE:
    4529             :         case DPLANE_OP_NONE:
    4530           0 :                 ret = -1;
    4531             :         }
    4532             : 
    4533           0 :         return ret;
    4534             : }
    4535             : 
    4536             : /*
    4537             :  * Update MAC, using dataplane context object.
    4538             :  */
    4539             : 
    4540           0 : enum netlink_msg_status netlink_put_mac_update_msg(struct nl_batch *bth,
    4541             :                                                    struct zebra_dplane_ctx *ctx)
    4542             : {
    4543           0 :         return netlink_batch_add_msg(bth, ctx, netlink_macfdb_update_ctx,
    4544             :                                      false);
    4545             : }
    4546             : 
    4547             : enum netlink_msg_status
    4548           0 : netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
    4549             : {
    4550           0 :         return netlink_batch_add_msg(bth, ctx, netlink_neigh_msg_encoder,
    4551             :                                      false);
    4552             : }
    4553             : 
    4554             : /*
    4555             :  * MPLS label forwarding table change via netlink interface, using dataplane
    4556             :  * context information.
    4557             :  */
    4558           0 : ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
    4559             :                                           void *buf, size_t buflen)
    4560             : {
    4561           0 :         mpls_lse_t lse;
    4562           0 :         const struct nhlfe_list_head *head;
    4563           0 :         const struct zebra_nhlfe *nhlfe;
    4564           0 :         struct nexthop *nexthop = NULL;
    4565           0 :         unsigned int nexthop_num;
    4566           0 :         const char *routedesc;
    4567           0 :         int route_type;
    4568           0 :         struct prefix p = {0};
    4569           0 :         struct nlsock *nl =
    4570           0 :                 kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
    4571             : 
    4572           0 :         struct {
    4573             :                 struct nlmsghdr n;
    4574             :                 struct rtmsg r;
    4575             :                 char buf[0];
    4576           0 :         } *req = buf;
    4577             : 
    4578           0 :         if (buflen < sizeof(*req))
    4579             :                 return 0;
    4580             : 
    4581           0 :         memset(req, 0, sizeof(*req));
    4582             : 
    4583             :         /*
    4584             :          * Count # nexthops so we can decide whether to use singlepath
    4585             :          * or multipath case.
    4586             :          */
    4587           0 :         nexthop_num = 0;
    4588           0 :         head = dplane_ctx_get_nhlfe_list(ctx);
    4589           0 :         frr_each(nhlfe_list_const, head, nhlfe) {
    4590           0 :                 nexthop = nhlfe->nexthop;
    4591           0 :                 if (!nexthop)
    4592           0 :                         continue;
    4593           0 :                 if (cmd == RTM_NEWROUTE) {
    4594             :                         /* Count all selected NHLFEs */
    4595           0 :                         if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
    4596           0 :                             && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
    4597           0 :                                 nexthop_num++;
    4598             :                 } else { /* DEL */
    4599             :                         /* Count all installed NHLFEs */
    4600           0 :                         if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
    4601           0 :                             && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
    4602           0 :                                 nexthop_num++;
    4603             :                 }
    4604             :         }
    4605             : 
    4606           0 :         if ((nexthop_num == 0) ||
    4607           0 :             (!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE)))
    4608           0 :                 return 0;
    4609             : 
    4610           0 :         req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    4611           0 :         req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
    4612           0 :         req->n.nlmsg_type = cmd;
    4613           0 :         req->n.nlmsg_pid = nl->snl.nl_pid;
    4614             : 
    4615           0 :         req->r.rtm_family = AF_MPLS;
    4616           0 :         req->r.rtm_table = RT_TABLE_MAIN;
    4617           0 :         req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
    4618           0 :         req->r.rtm_scope = RT_SCOPE_UNIVERSE;
    4619           0 :         req->r.rtm_type = RTN_UNICAST;
    4620             : 
    4621           0 :         if (cmd == RTM_NEWROUTE) {
    4622             :                 /* We do a replace to handle update. */
    4623           0 :                 req->n.nlmsg_flags |= NLM_F_REPLACE;
    4624             : 
    4625             :                 /* set the protocol value if installing */
    4626           0 :                 route_type = re_type_from_lsp_type(
    4627           0 :                         dplane_ctx_get_best_nhlfe(ctx)->type);
    4628           0 :                 req->r.rtm_protocol = zebra2proto(route_type);
    4629             :         }
    4630             : 
    4631             :         /* Fill destination */
    4632           0 :         lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1);
    4633           0 :         if (!nl_attr_put(&req->n, buflen, RTA_DST, &lse, sizeof(mpls_lse_t)))
    4634             :                 return 0;
    4635             : 
    4636             :         /* Fill nexthops (paths) based on single-path or multipath. The paths
    4637             :          * chosen depend on the operation.
    4638             :          */
    4639           0 :         if (nexthop_num == 1) {
    4640           0 :                 routedesc = "single-path";
    4641           0 :                 _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
    4642             :                                     routedesc);
    4643             : 
    4644           0 :                 nexthop_num = 0;
    4645           0 :                 frr_each(nhlfe_list_const, head, nhlfe) {
    4646           0 :                         nexthop = nhlfe->nexthop;
    4647           0 :                         if (!nexthop)
    4648           0 :                                 continue;
    4649             : 
    4650           0 :                         if ((cmd == RTM_NEWROUTE
    4651           0 :                              && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
    4652           0 :                                  && CHECK_FLAG(nexthop->flags,
    4653             :                                                NEXTHOP_FLAG_ACTIVE)))
    4654           0 :                             || (cmd == RTM_DELROUTE
    4655           0 :                                 && (CHECK_FLAG(nhlfe->flags,
    4656             :                                                NHLFE_FLAG_INSTALLED)
    4657           0 :                                     && CHECK_FLAG(nexthop->flags,
    4658             :                                                   NEXTHOP_FLAG_FIB)))) {
    4659             :                                 /* Add the gateway */
    4660           0 :                                 if (!_netlink_mpls_build_singlepath(
    4661             :                                             &p, routedesc, nhlfe, &req->n,
    4662             :                                             &req->r, buflen, cmd))
    4663             :                                         return false;
    4664             : 
    4665           0 :                                 nexthop_num++;
    4666             :                                 break;
    4667             :                         }
    4668             :                 }
    4669             :         } else { /* Multipath case */
    4670           0 :                 struct rtattr *nest;
    4671           0 :                 const union g_addr *src1 = NULL;
    4672             : 
    4673           0 :                 nest = nl_attr_nest(&req->n, buflen, RTA_MULTIPATH);
    4674           0 :                 if (!nest)
    4675           0 :                         return 0;
    4676             : 
    4677           0 :                 routedesc = "multipath";
    4678           0 :                 _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
    4679             :                                     routedesc);
    4680             : 
    4681           0 :                 nexthop_num = 0;
    4682           0 :                 frr_each(nhlfe_list_const, head, nhlfe) {
    4683           0 :                         nexthop = nhlfe->nexthop;
    4684           0 :                         if (!nexthop)
    4685           0 :                                 continue;
    4686             : 
    4687           0 :                         if ((cmd == RTM_NEWROUTE
    4688           0 :                              && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
    4689           0 :                                  && CHECK_FLAG(nexthop->flags,
    4690             :                                                NEXTHOP_FLAG_ACTIVE)))
    4691           0 :                             || (cmd == RTM_DELROUTE
    4692           0 :                                 && (CHECK_FLAG(nhlfe->flags,
    4693             :                                                NHLFE_FLAG_INSTALLED)
    4694           0 :                                     && CHECK_FLAG(nexthop->flags,
    4695             :                                                   NEXTHOP_FLAG_FIB)))) {
    4696           0 :                                 nexthop_num++;
    4697             : 
    4698             :                                 /* Build the multipath */
    4699           0 :                                 if (!_netlink_mpls_build_multipath(
    4700             :                                             &p, routedesc, nhlfe, &req->n,
    4701             :                                             buflen, &req->r, &src1))
    4702             :                                         return 0;
    4703             :                         }
    4704             :                 }
    4705             : 
    4706             :                 /* Add the multipath */
    4707           0 :                 nl_attr_nest_end(&req->n, nest);
    4708             :         }
    4709             : 
    4710           0 :         return NLMSG_ALIGN(req->n.nlmsg_len);
    4711             : }
    4712             : 
    4713             : /****************************************************************************
    4714             : * This code was developed in a branch that didn't have dplane APIs for
    4715             : * MAC updates. Hence the use of the legacy style. It will be moved to
    4716             : * the new dplane style pre-merge to master. XXX
    4717             : */
    4718           0 : static int netlink_fdb_nh_update(uint32_t nh_id, struct in_addr vtep_ip)
    4719             : {
    4720           0 :         struct {
    4721             :                 struct nlmsghdr n;
    4722             :                 struct nhmsg nhm;
    4723             :                 char buf[256];
    4724             :         } req;
    4725           0 :         int cmd = RTM_NEWNEXTHOP;
    4726           0 :         struct zebra_vrf *zvrf;
    4727           0 :         struct zebra_ns *zns;
    4728             : 
    4729           0 :         zvrf = zebra_vrf_get_evpn();
    4730           0 :         zns = zvrf->zns;
    4731             : 
    4732           0 :         memset(&req, 0, sizeof(req));
    4733             : 
    4734           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
    4735           0 :         req.n.nlmsg_flags = NLM_F_REQUEST;
    4736           0 :         req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
    4737           0 :         req.n.nlmsg_type = cmd;
    4738           0 :         req.nhm.nh_family = AF_INET;
    4739             : 
    4740           0 :         if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id))
    4741             :                 return -1;
    4742           0 :         if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0))
    4743             :                 return -1;
    4744           0 :         if (!nl_attr_put(&req.n, sizeof(req), NHA_GATEWAY,
    4745             :                         &vtep_ip, IPV4_MAX_BYTELEN))
    4746             :                 return -1;
    4747             : 
    4748           0 :         if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
    4749           0 :                 zlog_debug("Tx %s fdb-nh 0x%x %pI4",
    4750             :                            nl_msg_type_to_str(cmd), nh_id, &vtep_ip);
    4751             :         }
    4752             : 
    4753           0 :         return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
    4754             :                             false);
    4755             : }
    4756             : 
    4757           0 : static int netlink_fdb_nh_del(uint32_t nh_id)
    4758             : {
    4759           0 :         struct {
    4760             :                 struct nlmsghdr n;
    4761             :                 struct nhmsg nhm;
    4762             :                 char buf[256];
    4763             :         } req;
    4764           0 :         int cmd = RTM_DELNEXTHOP;
    4765           0 :         struct zebra_vrf *zvrf;
    4766           0 :         struct zebra_ns *zns;
    4767             : 
    4768           0 :         zvrf = zebra_vrf_get_evpn();
    4769           0 :         zns = zvrf->zns;
    4770             : 
    4771           0 :         memset(&req, 0, sizeof(req));
    4772             : 
    4773           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
    4774           0 :         req.n.nlmsg_flags = NLM_F_REQUEST;
    4775           0 :         req.n.nlmsg_type = cmd;
    4776           0 :         req.nhm.nh_family = AF_UNSPEC;
    4777             : 
    4778           0 :         if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id))
    4779             :                 return -1;
    4780             : 
    4781           0 :         if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
    4782           0 :                 zlog_debug("Tx %s fdb-nh 0x%x",
    4783             :                            nl_msg_type_to_str(cmd), nh_id);
    4784             :         }
    4785             : 
    4786           0 :         return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
    4787             :                             false);
    4788             : }
    4789             : 
    4790           0 : static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt,
    4791             :                 struct nh_grp *nh_ids)
    4792           0 : {
    4793           0 :         struct {
    4794             :                 struct nlmsghdr n;
    4795             :                 struct nhmsg nhm;
    4796             :                 char buf[256];
    4797             :         } req;
    4798           0 :         int cmd = RTM_NEWNEXTHOP;
    4799           0 :         struct zebra_vrf *zvrf;
    4800           0 :         struct zebra_ns *zns;
    4801           0 :         struct nexthop_grp grp[nh_cnt];
    4802           0 :         uint32_t i;
    4803             : 
    4804           0 :         zvrf = zebra_vrf_get_evpn();
    4805           0 :         zns = zvrf->zns;
    4806             : 
    4807           0 :         memset(&req, 0, sizeof(req));
    4808             : 
    4809           0 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
    4810           0 :         req.n.nlmsg_flags = NLM_F_REQUEST;
    4811           0 :         req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
    4812           0 :         req.n.nlmsg_type = cmd;
    4813           0 :         req.nhm.nh_family = AF_UNSPEC;
    4814             : 
    4815           0 :         if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nhg_id))
    4816             :                 return -1;
    4817           0 :         if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0))
    4818             :                 return -1;
    4819           0 :         memset(&grp, 0, sizeof(grp));
    4820           0 :         for (i = 0; i < nh_cnt; ++i) {
    4821           0 :                 grp[i].id = nh_ids[i].id;
    4822           0 :                 grp[i].weight = nh_ids[i].weight;
    4823             :         }
    4824           0 :         if (!nl_attr_put(&req.n, sizeof(req), NHA_GROUP,
    4825             :                         grp, nh_cnt * sizeof(struct nexthop_grp)))
    4826             :                 return -1;
    4827             : 
    4828             : 
    4829           0 :         if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
    4830           0 :                 char vtep_str[ES_VTEP_LIST_STR_SZ];
    4831           0 :                 char nh_buf[16];
    4832             : 
    4833           0 :                 vtep_str[0] = '\0';
    4834           0 :                 for (i = 0; i < nh_cnt; ++i) {
    4835           0 :                         snprintf(nh_buf, sizeof(nh_buf), "%u ",
    4836             :                                         grp[i].id);
    4837           0 :                         strlcat(vtep_str, nh_buf, sizeof(vtep_str));
    4838             :                 }
    4839             : 
    4840           0 :                 zlog_debug("Tx %s fdb-nhg 0x%x %s",
    4841             :                            nl_msg_type_to_str(cmd), nhg_id, vtep_str);
    4842             :         }
    4843             : 
    4844           0 :         return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
    4845             :                             false);
    4846             : }
    4847             : 
    4848           0 : static int netlink_fdb_nhg_del(uint32_t nhg_id)
    4849             : {
    4850           0 :         return netlink_fdb_nh_del(nhg_id);
    4851             : }
    4852             : 
    4853           0 : int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip)
    4854             : {
    4855           0 :         return netlink_fdb_nh_update(nh_id, vtep_ip);
    4856             : }
    4857             : 
    4858           0 : int kernel_del_mac_nh(uint32_t nh_id)
    4859             : {
    4860           0 :         return netlink_fdb_nh_del(nh_id);
    4861             : }
    4862             : 
    4863           0 : int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
    4864             :                 struct nh_grp *nh_ids)
    4865             : {
    4866           0 :         return netlink_fdb_nhg_update(nhg_id, nh_cnt, nh_ids);
    4867             : }
    4868             : 
    4869           0 : int kernel_del_mac_nhg(uint32_t nhg_id)
    4870             : {
    4871           0 :         return netlink_fdb_nhg_del(nhg_id);
    4872             : }
    4873             : 
    4874             : #endif /* HAVE_NETLINK */

Generated by: LCOV version v1.16-topotato