summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/rfapi/vnc_zebra.c3
-rw-r--r--doc/user/installation.rst3
-rw-r--r--doc/user/routemap.rst4
-rw-r--r--isisd/isis_bfd.c2
-rw-r--r--isisd/isis_snmp.c2
-rw-r--r--ospf6d/ospf6_auth_trailer.c8
-rw-r--r--ospf6d/ospf6_zebra.c27
-rwxr-xr-xospfclient/ospfclient.py53
-rw-r--r--ospfd/ospf_api.c9
-rw-r--r--ospfd/ospf_api.h11
-rw-r--r--ospfd/ospf_apiserver.c37
-rw-r--r--ospfd/ospf_apiserver.h4
-rw-r--r--ospfd/ospf_vty.c2
-rw-r--r--ospfd/ospfd.c5
-rw-r--r--pimd/pim6_mld.c2
-rw-r--r--pimd/pim6_mroute_msg.c184
-rw-r--r--pimd/pim_instance.h1
-rw-r--r--pimd/pim_mroute.c237
-rw-r--r--pimd/pim_mroute.h17
-rw-r--r--pimd/pim_mroute_msg.c242
-rw-r--r--pimd/pim_nht.c25
-rw-r--r--pimd/pim_pim.c100
-rw-r--r--pimd/pim_rpf.c9
-rw-r--r--pimd/pim_sock.c9
-rw-r--r--pimd/pim_upstream.c4
-rw-r--r--pimd/pim_zebra.c1
-rw-r--r--pimd/pim_zlookup.c7
-rw-r--r--pimd/pimd.c1
-rw-r--r--pimd/subdir.am2
-rwxr-xr-xtests/topotests/ospfapi/ctester.py36
-rw-r--r--tests/topotests/ospfapi/test_ospf_clientapi.py53
-rw-r--r--vtysh/vtysh_user.c4
-rw-r--r--zebra/debug_nl.c5
-rw-r--r--zebra/rt_netlink.c66
-rw-r--r--zebra/zebra_vxlan.c7
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));