diff options
35 files changed, 651 insertions, 531 deletions
diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index 672a0e9780..293f88d1df 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -628,7 +628,6 @@ static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd, struct rfapi_nve_group_cfg *rfg = rfd->rfg; afi_t afi = family2afi(rfd->vn_addr.addr_family); struct prefix nhp; - // struct prefix *nhpp; void *pAddr; vnc_zlog_debug_verbose("%s: entry, add=%d", __func__, add); @@ -660,7 +659,7 @@ static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd, return; } - pAddr = &nhp.u.prefix4; + pAddr = &nhp.u.val; /* * Loop over the list of NVE-Groups configured for diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 401a1f2721..ba35facf2a 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -231,7 +231,8 @@ options from the list below. Enable the support of Linux Realms. Convert tag values from 1-255 into a realm value when inserting into the Linux kernel. Then routing policy can be - assigned to the realm. See the tc man page. + assigned to the realm. See the tc man page. This option is currently not + compatible with the usage of nexthop groups in the linux kernel itself. .. option:: --disable-irdp diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 754b709173..05c9eeb755 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -244,7 +244,9 @@ Route Map Set Command Set a tag on the matched route. This tag value can be from (1-4294967295). Additionally if you have compiled with the :option:`--enable-realms` configure option. Tag values from (1-255) are sent to the Linux kernel as a - realm value. Then route policy can be applied. See the tc man page. + realm value. Then route policy can be applied. See the tc man page. As + a note realms cannot currently be used with the installation of nexthops + as nexthop groups in the linux kernel. .. clicmd:: set ip next-hop IPV4_ADDRESS diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index 5311a384e7..9e8267b6e8 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -206,7 +206,7 @@ static int bfd_handle_circuit_add_addr(struct isis_circuit *circuit) struct isis_adjacency *adj; struct listnode *node; - if (circuit->area == 0) + if (circuit->area == NULL) return 0; for (ALL_LIST_ELEMENTS_RO(circuit->area->adjacency_list, node, adj)) { diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index 3590044f85..a184b5b30a 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -2117,7 +2117,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name, switch (v->magic) { case ISIS_CIRC_IFINDEX: - if (circuit->interface == 0) + if (circuit->interface == NULL) return SNMP_INTEGER(0); return SNMP_INTEGER(circuit->interface->ifindex); diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c index 77ac4a1877..e54f6784e8 100644 --- a/ospf6d/ospf6_auth_trailer.c +++ b/ospf6d/ospf6_auth_trailer.c @@ -120,7 +120,13 @@ void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, ospf6_at_hdr = (struct ospf6_auth_hdr *)((uint8_t *)ospfh + oh_len); at_hdr_len = ntohs(ospf6_at_hdr->length); - hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE; + hash_len = at_hdr_len - (uint16_t)OSPF6_AUTH_HDR_MIN_SIZE; + if (hash_len > KEYCHAIN_MAX_HASH_SIZE) { + zlog_debug( + "Specified value for hash_len %u is greater than expected %u", + hash_len, KEYCHAIN_MAX_HASH_SIZE); + return; + } memcpy(temp, ospf6_at_hdr->data, hash_len); temp[hash_len] = '\0'; zlog_debug("OSPF6 Authentication Trailer"); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 8366716585..f1a4209a8e 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -432,9 +432,12 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request, } /* If removing is the best path and if there's another path, - treat this request as add the secondary path */ - if (type == REM && ospf6_route_is_best(request) && request->next - && ospf6_route_is_same(request, request->next)) { + * treat this request as add the secondary path - if there are + * nexthops. + */ + if (type == REM && ospf6_route_is_best(request) && request->next && + ospf6_route_is_same(request, request->next) && + ospf6_route_num_nexthops(request->next) > 0) { if (IS_OSPF6_DEBUG_ZEBRA(SEND)) zlog_debug( " Best-path removal resulted Secondary addition"); @@ -452,9 +455,12 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request, nhcount = ospf6_route_num_nexthops(request); if (nhcount == 0) { - if (IS_OSPF6_DEBUG_ZEBRA(SEND)) - zlog_debug(" No nexthop, ignore"); - return; + if (type == ADD) { + if (IS_OSPF6_DEBUG_ZEBRA(SEND)) + zlog_debug(" No nexthop, ignore"); + return; + } else if (IS_OSPF6_DEBUG_ZEBRA(SEND)) + zlog_debug(" No nexthop, rem ok"); } dest = &request->prefix; @@ -464,17 +470,20 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request, api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if (nhcount > ospf6->max_multipath) { if (IS_OSPF6_DEBUG_ZEBRA(SEND)) zlog_debug( " Nexthop count is greater than configured maximum-path, hence ignore the extra nexthops"); } + api.nexthop_num = MIN(nhcount, ospf6->max_multipath); + if (api.nexthop_num > 0) { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + ospf6_route_zebra_copy_nexthops(request, api.nexthops, + api.nexthop_num, api.vrf_id); + } - ospf6_route_zebra_copy_nexthops(request, api.nexthops, api.nexthop_num, - api.vrf_id); SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = (request->path.metric_type == 2 ? request->path.u.cost_e2 : request->path.cost); diff --git a/ospfclient/ospfclient.py b/ospfclient/ospfclient.py index be8b51f007..c7cfc88b9c 100755 --- a/ospfclient/ospfclient.py +++ b/ospfclient/ospfclient.py @@ -3,7 +3,7 @@ # # December 22 2021, Christian Hopps <chopps@labn.net> # -# Copyright 2021, LabN Consulting, L.L.C. +# Copyright 2021-2022, LabN Consulting, L.L.C. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -54,6 +54,7 @@ MSG_DELETE_REQUEST = 6 MSG_SYNC_REACHABLE = 7 MSG_SYNC_ISM = 8 MSG_SYNC_NSM = 9 +MSG_SYNC_ROUTER_ID = 19 smsg_info = { MSG_REGISTER_OPAQUETYPE: ("REGISTER_OPAQUETYPE", "BBxx"), @@ -65,6 +66,7 @@ smsg_info = { MSG_SYNC_REACHABLE: ("MSG_SYNC_REACHABLE", ""), MSG_SYNC_ISM: ("MSG_SYNC_ISM", ""), MSG_SYNC_NSM: ("MSG_SYNC_NSM", ""), + MSG_SYNC_ROUTER_ID: ("MSG_SYNC_ROUTER_ID", ""), } # -------------------------- @@ -80,6 +82,7 @@ MSG_DEL_IF = 15 MSG_ISM_CHANGE = 16 MSG_NSM_CHANGE = 17 MSG_REACHABLE_CHANGE = 18 +MSG_ROUTER_ID_CHANGE = 20 amsg_info = { MSG_REPLY: ("REPLY", "bxxx"), @@ -91,6 +94,7 @@ amsg_info = { MSG_ISM_CHANGE: ("ISM_CHANGE", ">IIBxxx"), MSG_NSM_CHANGE: ("NSM_CHANGE", ">IIIBxxx"), MSG_REACHABLE_CHANGE: ("REACHABLE_CHANGE", ">HH"), + MSG_ROUTER_ID_CHANGE: ("ROUTER_ID_CHANGE", ">I"), } OSPF_API_OK = 0 @@ -536,6 +540,11 @@ class OspfApiClient: logging.debug("SEND: %s: request NSM changes", self) await self.msg_send_raises(MSG_SYNC_NSM) + async def req_router_id_sync(self): + "Request a dump of the current NSM states of all neighbors." + logging.debug("SEND: %s: request router ID sync", self) + await self.msg_send_raises(MSG_SYNC_ROUTER_ID) + class OspfOpaqueClient(OspfApiClient): """A client connection to OSPF Daemon for manipulating Opaque LSA data. @@ -564,6 +573,7 @@ class OspfOpaqueClient(OspfApiClient): MSG_ISM_CHANGE: self._if_change_msg, MSG_NSM_CHANGE: self._nbr_change_msg, MSG_REACHABLE_CHANGE: self._reachable_msg, + MSG_ROUTER_ID_CHANGE: self._router_id_msg, } super().__init__(server, handlers) @@ -573,6 +583,9 @@ class OspfOpaqueClient(OspfApiClient): LSA_TYPE_OPAQUE_AREA: {}, LSA_TYPE_OPAQUE_AS: {}, } + self.router_id = ip(0) + self.router_id_change_cb = None + self.lsid_seq_num = {} self.lsa_change_cb = None @@ -775,6 +788,25 @@ class OspfOpaqueClient(OspfApiClient): logging.info("RECV: %s calling callback", api_msgname(mt)) await self.reachable_change_cb(router_ids[:nadd], router_ids[nadd:]) + async def _router_id_msg(self, mt, msg, extra, router_id): + router_id = ip(router_id) + logging.info("RECV: %s router ID %s", api_msgname(mt), router_id) + old_router_id = self.router_id + if old_router_id == router_id: + return + + self.router_id = router_id + logging.info( + "RECV: %s new router ID %s older router ID %s", + api_msgname(mt), + router_id, + old_router_id, + ) + + if self.router_id_change_cb: + logging.info("RECV: %s calling callback", api_msgname(mt)) + await self.router_id_change_cb(router_id, old_router_id) + async def add_opaque_data(self, addr, lsa_type, otype, oid, data): """Add an instance of opaque data. @@ -1022,6 +1054,25 @@ class OspfOpaqueClient(OspfApiClient): self.nsm_change_cb = callback await self.req_nsm_states() + async def monitor_router_id(self, callback=None): + """Monitor the OSPF router ID. + + The property `router_id` contains the OSPF urouter ID. + This value is updated prior to calling the `callback` + + Args: + callback: callback will be called when the router ID changes. + The callback signature is: + + `callback(new_router_id, old_router_id)` + + Args: + new_router_id: the new router ID + old_router_id: the old router ID + """ + self.router_id_change_cb = callback + await self.req_router_id_sync() + # ================ # CLI/Script Usage diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 99bc6c0b03..8636db450b 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -1,6 +1,7 @@ /* * API message handling module for OSPF daemon and client. * Copyright (C) 2001, 2002 Ralph Keller + * Copyright (c) 2022, LabN Consulting, L.L.C. * * This file is part of GNU Zebra. * @@ -682,4 +683,12 @@ struct msg *new_msg_reachable_change(uint32_t seqnum, uint16_t nadd, return msg_new(MSG_REACHABLE_CHANGE, nmsg, seqnum, len); } +struct msg *new_msg_router_id_change(uint32_t seqnum, struct in_addr router_id) +{ + struct msg_router_id_change rmsg = {.router_id = router_id}; + + return msg_new(MSG_ROUTER_ID_CHANGE, &rmsg, seqnum, + sizeof(struct msg_router_id_change)); +} + #endif /* SUPPORT_OSPF_API */ diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index 50b0c21c77..51c8c52ce5 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -1,6 +1,7 @@ /* * API message handling module for OSPF daemon and client. * Copyright (C) 2001, 2002 Ralph Keller + * Copyright (c) 2022, LabN Consulting, L.L.C. * * This file is part of GNU Zebra. * @@ -118,6 +119,7 @@ extern void msg_fifo_free(struct msg_fifo *fifo); #define MSG_SYNC_REACHABLE 7 #define MSG_SYNC_ISM 8 #define MSG_SYNC_NSM 9 +#define MSG_SYNC_ROUTER_ID 19 /* Messages from OSPF daemon. */ #define MSG_REPLY 10 @@ -129,6 +131,7 @@ extern void msg_fifo_free(struct msg_fifo *fifo); #define MSG_ISM_CHANGE 16 #define MSG_NSM_CHANGE 17 #define MSG_REACHABLE_CHANGE 18 +#define MSG_ROUTER_ID_CHANGE 20 struct msg_register_opaque_type { uint8_t lsatype; @@ -260,6 +263,10 @@ struct msg_reachable_change { struct in_addr router_ids[]; /* add followed by remove */ }; +struct msg_router_id_change { + struct in_addr router_id; /* this systems router id */ +}; + /* We make use of a union to define a structure that covers all possible API messages. This allows us to find out how much memory needs to be reserved for the largest API message. */ @@ -279,6 +286,7 @@ struct apimsg { struct msg_nsm_change nsm_change; struct msg_lsa_change_notify lsa_change_notify; struct msg_reachable_change reachable_change; + struct msg_router_id_change router_id_change; } u; }; @@ -338,6 +346,9 @@ extern struct msg *new_msg_reachable_change(uint32_t seqnum, uint16_t nadd, struct in_addr *add, uint16_t nremove, struct in_addr *remove); + +extern struct msg *new_msg_router_id_change(uint32_t seqnr, + struct in_addr router_id); /* string printing functions */ extern const char *ospf_api_errname(int errcode); extern const char *ospf_api_typename(int msgtype); diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 7c3fef4536..9d73c3dfe6 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -1,6 +1,7 @@ /* * Server side of OSPF API. * Copyright (C) 2001, 2002 Ralph Keller + * Copyright (c) 2022, LabN Consulting, L.L.C. * * This file is part of GNU Zebra. * @@ -727,6 +728,7 @@ static int ospf_apiserver_send_msg(struct ospf_apiserver *apiserv, case MSG_ISM_CHANGE: case MSG_NSM_CHANGE: case MSG_REACHABLE_CHANGE: + case MSG_ROUTER_ID_CHANGE: fifo = apiserv->out_async_fifo; fd = apiserv->fd_async; event = OSPF_APISERVER_ASYNC_WRITE; @@ -809,6 +811,9 @@ int ospf_apiserver_handle_msg(struct ospf_apiserver *apiserv, struct msg *msg) case MSG_SYNC_NSM: rc = ospf_apiserver_handle_sync_nsm(apiserv, msg); break; + case MSG_SYNC_ROUTER_ID: + rc = ospf_apiserver_handle_sync_router_id(apiserv, msg); + break; default: zlog_warn("ospf_apiserver_handle_msg: Unknown message type: %d", msg->hdr.msgtype); @@ -1479,6 +1484,23 @@ int ospf_apiserver_handle_sync_nsm(struct ospf_apiserver *apiserv, } +int ospf_apiserver_handle_sync_router_id(struct ospf_apiserver *apiserv, + struct msg *msg) +{ + struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + uint32_t seqnum = msg_get_seq(msg); + struct msg *m; + int _rc, rc = 0; + + m = new_msg_router_id_change(seqnum, ospf->router_id); + rc = ospf_apiserver_send_msg(apiserv, m); + msg_free(m); + + /* Send a reply back to client with return code */ + _rc = ospf_apiserver_send_reply(apiserv, seqnum, rc); + return rc ? rc : _rc; +} + /* ----------------------------------------------------------- * Following are functions to originate or update LSA * from an application. @@ -2679,4 +2701,19 @@ void ospf_apiserver_notify_reachable(struct route_table *ort, } +void ospf_apiserver_clients_notify_router_id_change(struct in_addr router_id) +{ + struct msg *msg; + + msg = new_msg_router_id_change(0, router_id); + if (!msg) { + zlog_warn("%s: new_msg_router_id_change failed", __func__); + return; + } + + ospf_apiserver_clients_notify_all(msg); + msg_free(msg); +} + + #endif /* SUPPORT_OSPF_API */ diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index 7d728ead93..e28202e46f 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -125,6 +125,8 @@ extern void ospf_apiserver_clients_notify_new_if(struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_del_if(struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_ism_change(struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_nsm_change(struct ospf_neighbor *nbr); +extern void +ospf_apiserver_clients_notify_router_id_change(struct in_addr router_id); extern int ospf_apiserver_is_ready_type9(struct ospf_interface *oi); extern int ospf_apiserver_is_ready_type10(struct ospf_area *area); @@ -157,6 +159,8 @@ extern int ospf_apiserver_handle_sync_ism(struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_sync_nsm(struct ospf_apiserver *apiserv, struct msg *msg); +extern int ospf_apiserver_handle_sync_router_id(struct ospf_apiserver *apiserv, + struct msg *msg); extern void ospf_apiserver_notify_reachable(struct route_table *ort, struct route_table *nrt); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 747643465c..5bb65b6abc 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -4343,7 +4343,7 @@ static void show_ip_ospf_neighbour_brief(struct vty *vty, char msgbuf[16]; char timebuf[OSPF_TIME_DUMP_SIZE]; json_object *json_neighbor = NULL, *json_neigh_array = NULL; - struct timeval res; + struct timeval res = {.tv_sec = 0, .tv_usec = 0}; long time_val = 0; char uptime[OSPF_TIME_DUMP_SIZE]; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 337456ecd8..33872950ac 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -61,6 +61,7 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_ldp_sync.h" #include "ospfd/ospf_gr.h" +#include "ospfd/ospf_apiserver.h" DEFINE_QOBJ_TYPE(ospf); @@ -241,6 +242,10 @@ void ospf_process_refresh_data(struct ospf *ospf, bool reset) } ospf_external_lsa_rid_change(ospf); + +#ifdef SUPPORT_OSPF_API + ospf_apiserver_clients_notify_router_id_change(router_id); +#endif } ospf->inst_shutdown = 0; diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index a67d33ca97..255fd62ba7 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -2198,7 +2198,7 @@ void gm_ifp_teardown(struct interface *ifp) static void gm_update_ll(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; - struct gm_if *gm_ifp = pim_ifp ? pim_ifp->mld : NULL; + struct gm_if *gm_ifp = pim_ifp->mld; bool was_querier; was_querier = diff --git a/pimd/pim6_mroute_msg.c b/pimd/pim6_mroute_msg.c deleted file mode 100644 index 0b4b31fefa..0000000000 --- a/pimd/pim6_mroute_msg.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * PIM for Quagga - * Copyright (C) 2022 Dell Technologies Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <zebra.h> -#include "log.h" -#include "privs.h" -#include "if.h" -#include "prefix.h" -#include "vty.h" -#include "plist.h" -#include "sockopt.h" -#include "lib_errors.h" -#include "lib/network.h" - -#include "pimd.h" -#include "pim_instance.h" -#include "pim_mroute.h" -#include "pim_oil.h" -#include "pim_str.h" -#include "pim_time.h" -#include "pim_iface.h" -#include "pim_macro.h" -#include "pim_rp.h" -#include "pim_oil.h" -#include "pim_ssm.h" -#include "pim_sock.h" - -int pim_mroute_set(struct pim_instance *pim, int enable) -{ - int err; - int opt, data; - socklen_t data_len = sizeof(data); - - /* - * We need to create the VRF table for the pim mroute_socket - */ - if (pim->vrf->vrf_id != VRF_DEFAULT) { - frr_with_privs (&pimd_privs) { - - data = pim->vrf->data.l.table_id; - err = setsockopt(pim->mroute_socket, PIM_IPPROTO, - MRT6_TABLE, &data, data_len); - if (err) { - zlog_warn( - "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT6_TABLE=%d): errno=%d: %s", - __FILE__, __func__, pim->mroute_socket, - data, errno, safe_strerror(errno)); - return -1; - } - } - } - - frr_with_privs (&pimd_privs) { - opt = enable ? MRT6_INIT : MRT6_DONE; - /* - * *BSD *cares* about what value we pass down - * here - */ - data = 1; - err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data, - data_len); - if (err) { - zlog_warn( - "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s", - __FILE__, __func__, pim->mroute_socket, - enable ? "MRT6_INIT" : "MRT6_DONE", data, errno, - safe_strerror(errno)); - return -1; - } - } - - if (enable) { - /* Linux and Solaris IPV6_PKTINFO */ - data = 1; - if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IPV6_RECVPKTINFO, - &data, data_len)) { - zlog_warn( - "Could not set IPV6_PKTINFO on socket fd=%d: errno=%d: %s", - pim->mroute_socket, errno, - safe_strerror(errno)); - } - } - - setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8); - - if (set_nonblocking (pim->mroute_socket) < 0) { - zlog_warn( - "Could not set non blocking on socket fd=%d: errno=%d: %s", - pim->mroute_socket, errno, - safe_strerror(errno)); - } - - if (enable) { -#if defined linux - int upcalls = MRT6MSG_WRMIFWHOLE; - opt = MRT6_PIM; - - err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls, - sizeof(upcalls)); - if (err) { - zlog_warn( - "Failure to register for WHOLE and WRONGMIF upcalls %d %s", - errno, safe_strerror(errno)); - return -1; - } -#else - zlog_warn( - "PIM-SM will not work properly on this platform, until the ability to receive the WHOLEPKT upcall"); -#endif - } - - return 0; -} -static const char *const mrt6msgtype2str[MRT6MSG_WRMIFWHOLE + 1] = { - "<unknown_upcall?>", "NOCACHE", "WRONGMIF", "WHOLEPKT", "WRMIFWHOLE"}; - -int pim_mroute_msg(struct pim_instance *pim, const char *buf, - size_t buf_size, ifindex_t ifindex) -{ - struct interface *ifp; - const struct ip6_hdr *ip6_hdr; - const struct mrt6msg *msg; - - if (buf_size < (int)sizeof(struct ip6_hdr)) - return 0; - - ip6_hdr = (const struct ip6_hdr *)buf; - - if ((ip6_hdr->ip6_vfc & 0xf) == 0) { - msg = (const struct mrt6msg *)buf; - - ifp = pim_if_find_by_vif_index(pim, msg->im6_mif); - - if (!ifp) - return 0; - if (PIM_DEBUG_MROUTE) { - zlog_debug( - "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s mifi=%d size=%ld", - __func__, mrt6msgtype2str[msg->im6_msgtype], - msg->im6_msgtype, ip6_hdr->ip6_nxt, - pim->mroute_socket, &msg->im6_src, - &msg->im6_dst, ifp->name, msg->im6_mif, - (long int)buf_size); - } - - switch (msg->im6_msgtype) { - case MRT6MSG_WRONGMIF: - return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp, - msg); - case MRT6MSG_NOCACHE: - return pim_mroute_msg_nocache(pim->mroute_socket, ifp, - msg); - case MRT6MSG_WHOLEPKT: - return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp, - (const char *)msg, - buf_size); - case MRT6MSG_WRMIFWHOLE: - return pim_mroute_msg_wrvifwhole(pim->mroute_socket, - ifp, (const char *)msg, - buf_size); - default: - break; - } - } - - return 0; -} - diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index b19e8208ba..23b9df4aff 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -88,6 +88,7 @@ struct pim_router { uint32_t register_suppress_time; int packet_process; uint32_t register_probe_time; + uint16_t multipath; /* * What is the default vrf that we work in diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 1978afa7c0..8f1e6184d0 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -26,6 +26,7 @@ #include "plist.h" #include "sockopt.h" #include "lib_errors.h" +#include "lib/network.h" #include "pimd.h" #include "pim_rpf.h" @@ -47,6 +48,111 @@ static void mroute_read_on(struct pim_instance *pim); +int pim_mroute_set(struct pim_instance *pim, int enable) +{ + int err; + int opt, data; + socklen_t data_len = sizeof(data); + + /* + * We need to create the VRF table for the pim mroute_socket + */ + if (pim->vrf->vrf_id != VRF_DEFAULT) { + frr_with_privs (&pimd_privs) { + + data = pim->vrf->data.l.table_id; + err = setsockopt(pim->mroute_socket, PIM_IPPROTO, + MRT_TABLE, &data, data_len); + if (err) { + zlog_warn( + "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s", + __FILE__, __func__, pim->mroute_socket, + data, errno, safe_strerror(errno)); + return -1; + } + } + } + + frr_with_privs (&pimd_privs) { + opt = enable ? MRT_INIT : MRT_DONE; + /* + * *BSD *cares* about what value we pass down + * here + */ + data = 1; + err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data, + data_len); + if (err) { + zlog_warn( + "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s", + __FILE__, __func__, pim->mroute_socket, + enable ? "MRT_INIT" : "MRT_DONE", data, errno, + safe_strerror(errno)); + return -1; + } + } + +#if defined(HAVE_IP_PKTINFO) + if (enable) { + /* Linux and Solaris IP_PKTINFO */ + data = 1; + if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IP_PKTINFO, + &data, data_len)) { + zlog_warn( + "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + pim->mroute_socket, errno, + safe_strerror(errno)); + } + } +#endif + +#if PIM_IPV == 6 + if (enable) { + /* Linux and Solaris IPV6_PKTINFO */ + data = 1; + if (setsockopt(pim->mroute_socket, PIM_IPPROTO, + IPV6_RECVPKTINFO, &data, data_len)) { + zlog_warn( + "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s", + pim->mroute_socket, errno, + safe_strerror(errno)); + } + } +#endif + setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8); + + if (set_nonblocking(pim->mroute_socket) < 0) { + zlog_warn( + "Could not set non blocking on socket fd=%d: errno=%d: %s", + pim->mroute_socket, errno, safe_strerror(errno)); + return -1; + } + + if (enable) { +#if defined linux + int upcalls = GMMSG_WRVIFWHOLE; + opt = MRT_PIM; + + err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls, + sizeof(upcalls)); + if (err) { + zlog_warn( + "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s", + errno, safe_strerror(errno)); + return -1; + } +#else + zlog_warn( + "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall"); +#endif + } + + return 0; +} + +static const char *const gmmsgtype2str[GMMSG_WRVIFWHOLE + 1] = { + "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"}; + int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg) { @@ -504,6 +610,137 @@ int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf, return 0; } +#if PIM_IPV == 4 +static int process_igmp_packet(struct pim_instance *pim, const char *buf, + size_t buf_size, ifindex_t ifindex) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + struct in_addr ifaddr; + struct gm_sock *igmp; + const struct prefix *connected_src; + const struct ip *ip_hdr = (const struct ip *)buf; + + /* We have the IP packet but we do not know which interface this + * packet was + * received on. Find the interface that is on the same subnet as + * the source + * of the IP packet. + */ + ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id); + + if (!ifp || !ifp->info) + return 0; + + connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src); + + if (!connected_src) { + if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug( + "Recv IGMP packet on interface: %s from a non-connected source: %pI4", + ifp->name, &ip_hdr->ip_src); + } + return 0; + } + + pim_ifp = ifp->info; + ifaddr = connected_src->u.prefix4; + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr); + + if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug( + "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4", + __func__, pim->vrf->name, ifp->name, igmp, + &ip_hdr->ip_src, &ip_hdr->ip_dst); + } + if (igmp) + pim_igmp_packet(igmp, (char *)buf, buf_size); + else if (PIM_DEBUG_IGMP_PACKETS) { + zlog_debug( + "No IGMP socket on interface: %s with connected source: %pFX", + ifp->name, connected_src); + } + return 0; +} +#endif + +int pim_mroute_msg(struct pim_instance *pim, const char *buf, size_t buf_size, + ifindex_t ifindex) +{ + struct interface *ifp; + const ipv_hdr *ip_hdr; + const kernmsg *msg; + + if (buf_size < (int)sizeof(ipv_hdr)) + return 0; + + ip_hdr = (const ipv_hdr *)buf; + +#if PIM_IPV == 4 + if (ip_hdr->ip_p == IPPROTO_IGMP) { + process_igmp_packet(pim, buf, buf_size, ifindex); + } else if (ip_hdr->ip_p) { + if (PIM_DEBUG_MROUTE_DETAIL) { + zlog_debug( + "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld", + __func__, ip_hdr->ip_p, &ip_hdr->ip_src, + &ip_hdr->ip_dst, (long int)buf_size); + } + + } else { +#else + + if ((ip_hdr->ip6_vfc & 0xf) == 0) { +#endif + msg = (const kernmsg *)buf; + + ifp = pim_if_find_by_vif_index(pim, msg->msg_im_vif); + + if (!ifp) + return 0; + if (PIM_DEBUG_MROUTE) { +#if PIM_IPV == 4 + zlog_debug( + "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld", + __func__, gmmsgtype2str[msg->msg_im_msgtype], + msg->msg_im_msgtype, ip_hdr->ip_p, + pim->mroute_socket, &msg->msg_im_src, + &msg->msg_im_dst, ifp->name, msg->msg_im_vif, + (long int)buf_size); +#else + zlog_debug( + "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld", + __func__, gmmsgtype2str[msg->msg_im_msgtype], + msg->msg_im_msgtype, ip_hdr->ip6_nxt, + pim->mroute_socket, &msg->msg_im_src, + &msg->msg_im_dst, ifp->name, msg->msg_im_vif, + (long int)buf_size); +#endif + } + + switch (msg->msg_im_msgtype) { + case GMMSG_WRONGVIF: + return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp, + msg); + case GMMSG_NOCACHE: + return pim_mroute_msg_nocache(pim->mroute_socket, ifp, + msg); + case GMMSG_WHOLEPKT: + return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp, + (const char *)msg, + buf_size); + case GMMSG_WRVIFWHOLE: + return pim_mroute_msg_wrvifwhole(pim->mroute_socket, + ifp, (const char *)msg, + buf_size); + default: + break; + } + } + + return 0; +} + static void mroute_read(struct thread *t) { struct pim_instance *pim; diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index 712c916994..d6798c52ad 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -56,6 +56,7 @@ typedef struct sioc_sg_req pim_sioc_sg_req; #define vc_lcl_ifindex vifc_lcl_ifindex #define vc_rmt_addr vifc_rmt_addr +#define msg_im_msgtype im_msgtype #define msg_im_vif im_vif #define msg_im_src im_src #define msg_im_dst im_dst @@ -64,6 +65,13 @@ typedef struct sioc_sg_req pim_sioc_sg_req; #define IGMPMSG_WRVIFWHOLE 4 /* For PIM processing */ #endif +#ifndef GMMSG_NOCACHE +#define GMMSG_NOCACHE IGMPMSG_NOCACHE /* For PIM processing */ +#define GMMSG_WHOLEPKT IGMPMSG_WHOLEPKT /* For PIM processing */ +#define GMMSG_WRONGVIF IGMPMSG_WRONGVIF /* For PIM processing */ +#define GMMSG_WRVIFWHOLE IGMPMSG_WRVIFWHOLE /* For PIM processing */ +#endif + #ifndef PIM_IPPROTO #define PIM_IPPROTO IPPROTO_IP #endif @@ -94,6 +102,7 @@ typedef struct sioc_sg_req pim_sioc_sg_req; #define MRT_VERSION MRT6_VERSION #define MRT_ASSERT MRT6_ASSERT #define MRT_PIM MRT6_PIM +#define MRT_TABLE MRT6_TABLE #endif #ifndef PIM_IPPROTO @@ -108,6 +117,13 @@ typedef struct sioc_sg_req pim_sioc_sg_req; #define MRT6MSG_WRMIFWHOLE 4 /* For PIM processing */ #endif +#ifndef GMMSG_NOCACHE +#define GMMSG_NOCACHE MRT6MSG_NOCACHE /* For PIM processing */ +#define GMMSG_WHOLEPKT MRT6MSG_WHOLEPKT /* For PIM processing */ +#define GMMSG_WRONGVIF MRT6MSG_WRONGMIF /* For PIM processing */ +#define GMMSG_WRVIFWHOLE MRT6MSG_WRMIFWHOLE /* For PIM processing */ +#endif + typedef struct mif6ctl pim_vifctl; typedef struct mrt6msg kernmsg; typedef mifi_t vifi_t; @@ -119,6 +135,7 @@ typedef struct sioc_sg_req6 pim_sioc_sg_req; #define vc_pifi mif6c_pifi #define vc_rate_limit vifc_rate_limit +#define msg_im_msgtype im6_msgtype #define msg_im_vif im6_mif #define msg_im_src im6_src #define msg_im_dst im6_dst diff --git a/pimd/pim_mroute_msg.c b/pimd/pim_mroute_msg.c deleted file mode 100644 index ef12ec7a49..0000000000 --- a/pimd/pim_mroute_msg.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * PIM for Quagga - * Copyright (C) 2022 Dell Technologies Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <zebra.h> -#include "log.h" -#include "privs.h" -#include "if.h" -#include "prefix.h" -#include "vty.h" -#include "plist.h" -#include "sockopt.h" -#include "lib_errors.h" -#include "lib/network.h" - -#include "pimd.h" -#include "pim_instance.h" -#include "pim_mroute.h" -#include "pim_oil.h" -#include "pim_str.h" -#include "pim_iface.h" -#include "pim_macro.h" -#include "pim_rp.h" -#include "pim_oil.h" -#include "pim_msg.h" -#include "pim_sock.h" - - -int pim_mroute_set(struct pim_instance *pim, int enable) -{ - int err; - int opt, data; - socklen_t data_len = sizeof(data); - - /* - * We need to create the VRF table for the pim mroute_socket - */ - if (pim->vrf->vrf_id != VRF_DEFAULT) { - frr_with_privs(&pimd_privs) { - - data = pim->vrf->data.l.table_id; - err = setsockopt(pim->mroute_socket, PIM_IPPROTO, - MRT_TABLE, &data, data_len); - if (err) { - zlog_warn( - "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s", - __FILE__, __func__, pim->mroute_socket, - data, errno, safe_strerror(errno)); - return -1; - } - - } - } - - frr_with_privs(&pimd_privs) { - opt = enable ? MRT_INIT : MRT_DONE; - /* - * *BSD *cares* about what value we pass down - * here - */ - data = 1; - err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data, - data_len); - if (err) { - zlog_warn( - "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s", - __FILE__, __func__, pim->mroute_socket, - enable ? "MRT_INIT" : "MRT_DONE", data, errno, - safe_strerror(errno)); - return -1; - } - } - -#if defined(HAVE_IP_PKTINFO) - if (enable) { - /* Linux and Solaris IP_PKTINFO */ - data = 1; - if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IP_PKTINFO, - &data, data_len)) { - zlog_warn( - "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", - pim->mroute_socket, errno, - safe_strerror(errno)); - } - } -#endif - - setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8); - - if (set_nonblocking (pim->mroute_socket) < 0) { - zlog_warn( - "Could not set non blocking on socket fd=%d: errno=%d: %s", - pim->mroute_socket, errno, - safe_strerror(errno)); - } - - if (enable) { -#if defined linux - int upcalls = IGMPMSG_WRVIFWHOLE; - opt = MRT_PIM; - - err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls, - sizeof(upcalls)); - if (err) { - zlog_warn( - "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s", - errno, safe_strerror(errno)); - return -1; - } -#else - zlog_warn( - "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall"); -#endif - - } - - return 0; -} - -static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = { - "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"}; - - -int pim_mroute_msg(struct pim_instance *pim, const char *buf, - size_t buf_size, ifindex_t ifindex) -{ - struct interface *ifp; - const struct ip *ip_hdr; - const struct igmpmsg *msg; - - if (buf_size < (int)sizeof(struct ip)) - return 0; - - ip_hdr = (const struct ip *)buf; - - if (ip_hdr->ip_p == IPPROTO_IGMP) { - struct pim_interface *pim_ifp; - struct in_addr ifaddr; - struct gm_sock *igmp; - const struct prefix *connected_src; - - /* We have the IP packet but we do not know which interface this - * packet was - * received on. Find the interface that is on the same subnet as - * the source - * of the IP packet. - */ - ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id); - - if (!ifp || !ifp->info) - return 0; - - connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src); - - if (!connected_src) { - if (PIM_DEBUG_IGMP_PACKETS) { - zlog_debug( - "Recv IGMP packet on interface: %s from a non-connected source: %pI4", - ifp->name, &ip_hdr->ip_src); - } - return 0; - } - - pim_ifp = ifp->info; - ifaddr = connected_src->u.prefix4; - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, - ifaddr); - - if (PIM_DEBUG_IGMP_PACKETS) { - zlog_debug( - "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4", - __func__, pim->vrf->name, ifp->name, igmp, - &ip_hdr->ip_src, &ip_hdr->ip_dst); - } - if (igmp) - pim_igmp_packet(igmp, (char *)buf, buf_size); - else if (PIM_DEBUG_IGMP_PACKETS) { - zlog_debug( - "No IGMP socket on interface: %s with connected source: %pFX", - ifp->name, connected_src); - } - } else if (ip_hdr->ip_p) { - if (PIM_DEBUG_MROUTE_DETAIL) { - zlog_debug( - "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld", - __func__, ip_hdr->ip_p, &ip_hdr->ip_src, - &ip_hdr->ip_dst, (long int)buf_size); - } - - } else { - msg = (const struct igmpmsg *)buf; - - ifp = pim_if_find_by_vif_index(pim, msg->im_vif); - - if (!ifp) - return 0; - if (PIM_DEBUG_MROUTE) { - zlog_debug( - "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld", - __func__, igmpmsgtype2str[msg->im_msgtype], - msg->im_msgtype, ip_hdr->ip_p, - pim->mroute_socket, &msg->im_src, &msg->im_dst, - ifp->name, msg->im_vif, (long int)buf_size); - } - - switch (msg->im_msgtype) { - case IGMPMSG_WRONGVIF: - return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp, - msg); - case IGMPMSG_NOCACHE: - return pim_mroute_msg_nocache(pim->mroute_socket, ifp, - msg); - case IGMPMSG_WHOLEPKT: - return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp, - (const char *)msg, - buf_size); - case IGMPMSG_WRVIFWHOLE: - return pim_mroute_msg_wrvifwhole(pim->mroute_socket, - ifp, (const char *)msg, - buf_size); - default: - break; - } - } - - return 0; -} diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 22716c2a92..564d16a60b 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -304,15 +304,15 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, * "check cache or get immediate result." But until that can * be worked in, here's a copy of the code below :( */ - struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; + struct pim_zlookup_nexthop nexthop_tab[router->multipath]; ifindex_t i; struct interface *ifp = NULL; int num_ifindex; memset(nexthop_tab, 0, sizeof(nexthop_tab)); - num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, - MULTIPATH_NUM, bsr_addr, - PIM_NEXTHOP_LOOKUP_MAX); + num_ifindex = zclient_lookup_nexthop( + pim, nexthop_tab, router->multipath, bsr_addr, + PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex <= 0) return false; @@ -501,8 +501,8 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, struct prefix *src, struct prefix *grp, int neighbor_needed) { - struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL; - struct interface *ifps[MULTIPATH_NUM]; + struct pim_neighbor *nbrs[router->multipath], *nbr = NULL; + struct interface *ifps[router->multipath]; struct nexthop *nh_node = NULL; ifindex_t first_ifindex; struct interface *ifp = NULL; @@ -888,11 +888,11 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, struct prefix *grp, int neighbor_needed) { struct pim_nexthop_cache *pnc; - struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; - struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL; + struct pim_zlookup_nexthop nexthop_tab[router->multipath]; + struct pim_neighbor *nbrs[router->multipath], *nbr = NULL; struct pim_rpf rpf; int num_ifindex; - struct interface *ifps[MULTIPATH_NUM], *ifp; + struct interface *ifps[router->multipath], *ifp; int first_ifindex; int found = 0; uint8_t i = 0; @@ -915,9 +915,10 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, } memset(nexthop_tab, 0, - sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, - src_addr, PIM_NEXTHOP_LOOKUP_MAX); + sizeof(struct pim_zlookup_nexthop) * router->multipath); + num_ifindex = + zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, + src_addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { if (PIM_DEBUG_PIM_NHT) zlog_warn( diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index f0f4a7139b..1dd99d7ecd 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -42,6 +42,7 @@ #include "pim_register.h" #include "pim_errors.h" #include "pim_bsm.h" +#include <lib/lib_errors.h> static void on_pim_hello_send(struct thread *t); @@ -551,6 +552,7 @@ void pim_sock_reset(struct interface *ifp) static uint16_t ip_id = 0; #endif +#if PIM_IPV == 4 static int pim_msg_send_frame(int fd, char *buf, size_t len, struct sockaddr *dst, size_t salen, const char *ifname) @@ -558,7 +560,6 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len, if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0) return 0; -#if PIM_IPV == 4 if (errno == EMSGSIZE) { struct ip *ip = (struct ip *)buf; size_t hdrsize = sizeof(struct ip); @@ -585,7 +586,6 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len, return pim_msg_send_frame(fd, (char *)ip2, sendlen, dst, salen, ifname); } -#endif zlog_warn( "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m", @@ -593,16 +593,65 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len, return -1; } +#else +static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, + struct iovec *message, int fd) +{ + int retval; + struct msghdr smsghdr = {}; + struct cmsghdr *scmsgp; + union cmsgbuf { + struct cmsghdr hdr; + uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + }; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 dst_sin6 = {}; + + union cmsgbuf cmsg_buf = {}; + + /* destination address */ + dst_sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + dst_sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /*SIN6_LEN*/ + dst_sin6.sin6_addr = dst; + dst_sin6.sin6_scope_id = ifindex; + + /* send msg hdr */ + smsghdr.msg_iov = message; + smsghdr.msg_iovlen = 1; + smsghdr.msg_name = (caddr_t)&dst_sin6; + smsghdr.msg_namelen = sizeof(dst_sin6); + smsghdr.msg_control = (caddr_t)&cmsg_buf.buf; + smsghdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + smsghdr.msg_flags = 0; + + scmsgp = CMSG_FIRSTHDR(&smsghdr); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_PKTINFO; + scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); + pktinfo->ipi6_ifindex = ifindex; + pktinfo->ipi6_addr = src; + + retval = sendmsg(fd, &smsghdr, 0); + if (retval < 0) + flog_err( + EC_LIB_SOCKET, + "sendmsg failed: source: %pI6 Dest: %pI6 ifindex: %d: %s (%d)", + &src, &dst, ifindex, safe_strerror(errno), errno); + + return retval; +} +#endif + int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp) { - socklen_t tolen; - unsigned char buffer[10000]; - unsigned char *msg_start; - uint8_t ttl; - struct pim_msg_header *header; struct pim_interface *pim_ifp; + pim_ifp = ifp->info; if (pim_ifp->pim_passive_enable) { @@ -613,9 +662,15 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, return 0; } +#if PIM_IPV == 4 + uint8_t ttl; + struct pim_msg_header *header; + unsigned char buffer[10000]; + memset(buffer, 0, 10000); header = (struct pim_msg_header *)pim_msg; + /* * Omnios apparently doesn't have a #define for IP default * ttl that is the same as all other platforms. @@ -643,10 +698,11 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, break; } -#if PIM_IPV == 4 struct ip *ip = (struct ip *)buffer; struct sockaddr_in to = {}; int sendlen = sizeof(*ip) + pim_msg_size; + socklen_t tolen; + unsigned char *msg_start; ip->ip_id = htons(++ip_id); ip->ip_hl = 5; @@ -661,23 +717,6 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, to.sin_family = AF_INET; to.sin_addr = dst; tolen = sizeof(to); -#else - struct ip6_hdr *ip = (struct ip6_hdr *)buffer; - struct sockaddr_in6 to = {}; - int sendlen = sizeof(*ip) + pim_msg_size; - - ip->ip6_flow = 0; - ip->ip6_vfc = (6 << 4) | (IPTOS_PREC_INTERNETCONTROL >> 4); - ip->ip6_plen = htons(pim_msg_size); - ip->ip6_nxt = PIM_IP_PROTO_PIM; - ip->ip6_hlim = ttl; - ip->ip6_src = src; - ip->ip6_dst = dst; - - to.sin6_family = AF_INET6; - to.sin6_addr = dst; - tolen = sizeof(to); -#endif msg_start = buffer + sizeof(*ip); memcpy(msg_start, pim_msg, pim_msg_size); @@ -694,6 +733,17 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, tolen, ifp->name); return 0; + +#else + struct iovec iovector[2]; + + iovector[0].iov_base = pim_msg; + iovector[0].iov_len = pim_msg_size; + + pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); + + return 0; +#endif } static int hello_send(struct interface *ifp, uint16_t holdtime) diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index c470bcd4d7..bd4dd31a2c 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -54,7 +54,7 @@ void pim_rpf_set_refresh_time(struct pim_instance *pim) bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim_addr addr, int neighbor_needed) { - struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; + struct pim_zlookup_nexthop nexthop_tab[router->multipath]; struct pim_neighbor *nbr = NULL; int num_ifindex; struct interface *ifp = NULL; @@ -92,9 +92,10 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, } memset(nexthop_tab, 0, - sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, - addr, PIM_NEXTHOP_LOOKUP_MAX); + sizeof(struct pim_zlookup_nexthop) * router->multipath); + num_ifindex = + zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, + addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { zlog_warn( "%s %s: could not find nexthop ifindex for address %pPAs", diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 321775cce3..afc5d47118 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -70,18 +70,13 @@ int pim_socket_raw(int protocol) void pim_socket_ip_hdr(int fd) { - const int on = 1; - frr_with_privs(&pimd_privs) { #if PIM_IPV == 4 + const int on = 1; + if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) zlog_err("%s: Could not turn on IP_HDRINCL option: %m", __func__); -#else - if (setsockopt(fd, IPPROTO_IPV6, IPV6_HDRINCL, &on, sizeof(on))) - zlog_err( - "%s: Could not turn on IPV6_HDRINCL option: %m", - __func__); #endif } } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 3817d5d9e1..54a7f59ca4 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1948,8 +1948,8 @@ void pim_upstream_terminate(struct pim_instance *pim) struct pim_upstream *up; while ((up = rb_pim_upstream_first(&pim->upstream_head))) { - pim_upstream_del(pim, up, __func__); - pim_upstream_timers_stop(up); + if (pim_upstream_del(pim, up, __func__)) + pim_upstream_timers_stop(up); } rb_pim_upstream_fini(&pim->upstream_head); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 4135ae0408..7f217d9c2e 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -452,6 +452,7 @@ static void pim_zebra_connected(struct zclient *zclient) static void pim_zebra_capabilities(struct zclient_capabilities *cap) { router->mlag_role = cap->role; + router->multipath = cap->ecmp; } static zclient_handler *const pim_handlers[] = { diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index a3978bd0d2..87cf434133 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -211,7 +211,7 @@ static int zclient_read_nexthop(struct pim_instance *pim, metric = stream_getl(s); nexthop_num = stream_getc(s); - if (nexthop_num < 1) { + if (nexthop_num < 1 || nexthop_num > router->multipath) { if (PIM_DEBUG_PIM_NHT_DETAIL) zlog_debug("%s: socket %d bad nexthop_num=%d", __func__, zlookup->sock, nexthop_num); @@ -258,8 +258,9 @@ static int zclient_read_nexthop(struct pim_instance *pim, nexthop_tab[num_ifindex].ifindex = nh_ifi; ++num_ifindex; #else - zlog_warn("cannot use IPv4 nexthop %pI4 for IPv6 %pPA", - &nh_ip4, &addr); + zlog_warn( + "cannot use IPv4 nexthop %pI4(%d) for IPv6 %pPA", + &nh_ip4, nh_ifi, &addr); #endif break; case NEXTHOP_TYPE_IPV6_IFINDEX: diff --git a/pimd/pimd.c b/pimd/pimd.c index 58e874fd11..a3be3f66e1 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -100,6 +100,7 @@ void pim_router_init(void) router->debugs = 0; router->master = frr_init(); router->t_periodic = PIM_DEFAULT_T_PERIODIC; + router->multipath = MULTIPATH_NUM; /* RFC 4601: 4.6.3. Assert Metrics diff --git a/pimd/subdir.am b/pimd/subdir.am index 4dd63f6b88..1424b2a45b 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -78,7 +78,6 @@ pimd_pimd_SOURCES = \ pimd/pim_msdp_socket.c \ pimd/pim_signals.c \ pimd/pim_zpthread.c \ - pimd/pim_mroute_msg.c \ # end nodist_pimd_pimd_SOURCES = \ @@ -93,7 +92,6 @@ pimd_pim6d_SOURCES = \ pimd/pim6_mld.c \ pimd/pim6_stubs.c \ pimd/pim6_cmd.c \ - pimd/pim6_mroute_msg.c \ # end nodist_pimd_pim6d_SOURCES = \ diff --git a/tests/topotests/ospfapi/ctester.py b/tests/topotests/ospfapi/ctester.py index 243fc0613f..8fd202a023 100755 --- a/tests/topotests/ospfapi/ctester.py +++ b/tests/topotests/ospfapi/ctester.py @@ -42,6 +42,35 @@ sys.path[0:0] = [CLIENTDIR] import ospfclient as api # pylint: disable=E0401 # noqa: E402 +async def do_monitor(c, args): + cv = asyncio.Condition() + + async def cb(new_router_id, _): + assert new_router_id == c.router_id + logging.info("NEW ROUTER ID: %s", new_router_id) + sys.stdout.flush() + async with cv: + cv.notify_all() + + logging.debug("API using monitor router ID callback") + await c.monitor_router_id(callback=cb) + + for check in args.monitor: + logging.info("Waiting for %s", check) + + while True: + async with cv: + got = c.router_id + if str(check) == str(got): + break + logging.debug("expected '%s' != '%s'\nwaiting on notify", check, got) + await cv.wait() + + logging.info("SUCCESS: %s", check) + print("SUCCESS: {}".format(check)) + sys.stdout.flush() + + async def do_wait(c, args): cv = asyncio.Condition() @@ -51,7 +80,7 @@ async def do_wait(c, args): async with cv: cv.notify_all() - logging.debug("API using callback") + logging.debug("API using monitor reachable callback") await c.monitor_reachable(callback=cb) for w in args.wait: @@ -81,6 +110,8 @@ async def async_main(args): c._handle_msg_loop() # pylint: disable=W0212 ) + if args.monitor: + await do_monitor(c, args) if args.wait: await do_wait(c, args) return 0 @@ -88,6 +119,9 @@ async def async_main(args): def main(*args): ap = argparse.ArgumentParser(args) + ap.add_argument( + "--monitor", action="append", help="monitor and wait for this router ID" + ) ap.add_argument("--server", default="localhost", help="OSPF API server") ap.add_argument( "--wait", action="append", help="wait for comma-sep set of reachable routers" diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index dca91412dc..631c8025b5 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 eval: (blacken-mode 1) -*- # -# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2021-2022, LabN Consulting, L.L.C. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -61,7 +61,10 @@ assert os.path.exists( def _tgen(request): "Setup/Teardown the environment and provide tgen argument to tests" nrouters = request.param - topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)} + if nrouters == 1: + topodef = {"sw1:": ("r1",)} + else: + topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)} tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() @@ -183,6 +186,52 @@ def test_ospf_reachability(tgen): _test_reachability(tgen, testbin) +def _test_router_id(tgen, testbin): + r1 = tgen.gears["r1"] + waitlist = [ + "192.168.0.1", + "1.1.1.1", + "192.168.0.1", + ] + + mon_args = [f"--monitor={x}" for x in waitlist] + + p = None + try: + step("router id: check for initial router id") + p = r1.popen( + ["/usr/bin/timeout", "120", testbin, "-v", *mon_args], + encoding=None, # don't buffer + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + _wait_output(p, "SUCCESS: {}".format(waitlist[0])) + + step("router id: check for modified router id") + r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.1.1.1") + _wait_output(p, "SUCCESS: {}".format(waitlist[1])) + + step("router id: check for restored router id") + r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 192.168.0.1") + _wait_output(p, "SUCCESS: {}".format(waitlist[2])) + except Exception as error: + logging.error("ERROR: %s", error) + raise + finally: + if p: + p.terminate() + p.wait() + + +@pytest.mark.parametrize("tgen", [2], indirect=True) +def test_ospf_router_id(tgen): + testbin = os.path.join(TESTDIR, "ctester.py") + rc, o, e = tgen.gears["r1"].net.cmd_status([testbin, "--help"]) + logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) + _test_router_id(tgen, testbin) + + def _test_add_data(tgen, apibin): "Test adding opaque data to domain" diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 665e6ca90d..1ed284809e 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -71,6 +71,10 @@ static int vtysh_pam(const char *user) fprintf(stderr, "vtysh_pam: Failure to initialize pam: %s(%d)", pam_strerror(pamh, ret), ret); + if (pam_acct_mgmt(pamh, 0) != PAM_SUCCESS) + fprintf(stderr, "%s: Failed in account validation: %s(%d)", + __func__, pam_strerror(pamh, ret), ret); + /* close Linux-PAM */ if (pam_end(pamh, ret) != PAM_SUCCESS) { pamh = NULL; diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index 89ef7a2076..f8b866cd25 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -1083,8 +1083,9 @@ next_rta: plen = RTA_PAYLOAD(rta); zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, - plen, rta->rta_type, rtm_rta2str(rta->rta_type)); - switch (rta->rta_type) { + plen, rta->rta_type & NLA_TYPE_MASK, + rtm_rta2str(rta->rta_type & NLA_TYPE_MASK)); + switch (rta->rta_type & NLA_TYPE_MASK) { case RTA_IIF: case RTA_OIF: case RTA_PRIORITY: diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index be7feb21a3..ad9e13a0f8 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1641,6 +1641,27 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, return true; } +/* This function appends tag value as rtnl flow attribute + * to the given netlink msg only if value is less than 256. + * Used only if SUPPORT_REALMS enabled. + * + * @param nlmsg: nlmsghdr structure to fill in. + * @param maxlen: The size allocated for the message. + * @param tag: The route tag. + * + * The function returns true if the flow attribute could + * be added to the message, otherwise false is returned. + */ +static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, + route_tag_t tag) +{ + if (tag > 0 && tag <= 255) { + if (!nl_attr_put32(n, maxlen, RTA_FLOW, tag)) + return false; + } + return true; +} + /* This function takes a nexthop as argument and * appends to the given netlink msg. If the nexthop * defines a preferred source, the src parameter @@ -1659,12 +1680,10 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, * The function returns true if the nexthop could be added * to the message, otherwise false is returned. */ -static bool _netlink_route_build_multipath(const struct prefix *p, - const char *routedesc, int bytelen, - const struct nexthop *nexthop, - struct nlmsghdr *nlmsg, - size_t req_size, struct rtmsg *rtmsg, - const union g_addr **src) +static bool _netlink_route_build_multipath( + const struct prefix *p, const char *routedesc, int bytelen, + const struct nexthop *nexthop, struct nlmsghdr *nlmsg, size_t req_size, + struct rtmsg *rtmsg, const union g_addr **src, route_tag_t tag) { char label_buf[256]; struct vrf *vrf; @@ -1770,6 +1789,9 @@ static bool _netlink_route_build_multipath(const struct prefix *p, if (nexthop->weight) rtnh->rtnh_hops = nexthop->weight - 1; + if (!_netlink_set_tag(nlmsg, req_size, tag)) + return false; + nl_attr_rtnh_end(nlmsg, rtnh); return true; } @@ -1804,7 +1826,7 @@ _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc, bytelen = (family == AF_INET ? 4 : 16); return _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop, nlmsg, req_size, - rtmsg, src); + rtmsg, src, 0); } static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) @@ -1928,6 +1950,7 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, const struct prefix *p, *src_p; uint32_t table_id; struct nlsock *nl; + route_tag_t tag = 0; struct { struct nlmsghdr n; @@ -1999,20 +2022,12 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, return 0; #if defined(SUPPORT_REALMS) - { - route_tag_t tag; - - if (cmd == RTM_DELROUTE) - tag = dplane_ctx_get_old_tag(ctx); - else - tag = dplane_ctx_get_tag(ctx); - - if (tag > 0 && tag <= 255) { - if (!nl_attr_put32(&req->n, datalen, RTA_FLOW, tag)) - return 0; - } - } + if (cmd == RTM_DELROUTE) + tag = dplane_ctx_get_old_tag(ctx); + else + tag = dplane_ctx_get_tag(ctx); #endif + /* Table corresponding to this route. */ table_id = dplane_ctx_get_table(ctx); if (table_id < 256) @@ -2035,8 +2050,11 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, * prefix information to tell the kernel to schwack * it. */ - if (cmd == RTM_DELROUTE) + if (cmd == RTM_DELROUTE) { + if (!_netlink_set_tag(&req->n, datalen, tag)) + return 0; return NLMSG_ALIGN(req->n.nlmsg_len); + } if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) { struct rtattr *nest; @@ -2151,6 +2169,9 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, ? "recursive, single-path" : "single-path"; + if (!_netlink_set_tag(&req->n, datalen, tag)) + return 0; + if (!_netlink_route_build_singlepath( p, routedesc, bytelen, nexthop, &req->n, &req->r, datalen, cmd)) @@ -2210,7 +2231,8 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, if (!_netlink_route_build_multipath( p, routedesc, bytelen, nexthop, - &req->n, datalen, &req->r, &src1)) + &req->n, datalen, &req->r, &src1, + tag)) return 0; if (!setsrc && src1) { diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 927df14fbe..4cf309f7fc 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -5273,10 +5273,6 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, add ? "ADD" : "DEL"); if (add) { - - /* Remove L2VNI if present */ - zebra_vxlan_handle_vni_transition(zvrf, vni, add); - /* check if the vni is already present under zvrf */ if (zvrf->l3vni) { snprintf(err, err_str_sz, @@ -5292,6 +5288,9 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, return -1; } + /* Remove L2VNI if present */ + zebra_vxlan_handle_vni_transition(zvrf, vni, add); + /* add the L3-VNI to the global table */ zl3vni = zl3vni_add(vni, zvrf_id(zvrf)); |
