summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_route.c15
-rw-r--r--lib/northbound_oper.c85
-rw-r--r--pimd/pim_autorp.c63
-rw-r--r--pimd/pim_autorp.h1
-rw-r--r--pimd/pim_iface.c7
-rw-r--r--pimd/pim_instance.c7
-rw-r--r--pimd/pim_mroute.c10
-rw-r--r--tests/lib/northbound/test_oper_data.in4
-rw-r--r--tests/lib/northbound/test_oper_data.refout30
-rw-r--r--tests/topotests/pim_autorp/test_pim_autorp.py97
10 files changed, 223 insertions, 96 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1b30487bc3..39172cc082 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3195,21 +3195,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
bgp_path_info_unset_flag(dest, look_thru,
BGP_PATH_DMED_CHECK);
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED) &&
- (!CHECK_FLAG(look_thru->flags,
- BGP_PATH_DMED_SELECTED))) {
- bgp_path_info_unset_flag(dest, look_thru,
- BGP_PATH_DMED_CHECK);
- if (debug)
- zlog_debug("%s: %pBD(%s) pi %s dmed",
- __func__, dest,
- bgp->name_pretty,
- look_thru->peer->host);
-
- worse = look_thru;
- continue;
- }
-
reason = dest->reason;
any_comparisons = true;
if (bgp_path_info_cmp(bgp, first, look_thru, &paths_eq,
diff --git a/lib/northbound_oper.c b/lib/northbound_oper.c
index 6336db502a..b7815b001a 100644
--- a/lib/northbound_oper.c
+++ b/lib/northbound_oper.c
@@ -140,6 +140,11 @@ nb_op_create_yield_state(const char *xpath, struct yang_translator *translator,
ys = XCALLOC(MTYPE_NB_YIELD_STATE, sizeof(*ys));
ys->xpath = darr_strdup_cap(xpath, (size_t)XPATH_MAXLEN);
+ /* remove trailing '/'s */
+ while (darr_len(ys->xpath) > 1 && ys->xpath[darr_len(ys->xpath) - 2] == '/') {
+ darr_setlen(ys->xpath, darr_len(ys->xpath) - 1);
+ *darr_last(ys->xpath) = 0;
+ }
ys->xpath_orig = darr_strdup(xpath);
ys->translator = translator;
ys->flags = flags;
@@ -417,8 +422,7 @@ static enum nb_error nb_op_ys_finalize_node_info(struct nb_op_yield_state *ys,
/* Assert that we are walking the rightmost branch */
assert(!inner->parent || inner == inner->parent->child->prev);
- if (CHECK_FLAG(inner->schema->nodetype,
- LYS_CASE | LYS_CHOICE | LYS_CONTAINER)) {
+ if (CHECK_FLAG(inner->schema->nodetype, LYS_CONTAINER)) {
/* containers have only zero or one child on a branch of a tree */
inner = ((struct lyd_node_inner *)inner)->child;
assert(!inner || inner->prev == inner);
@@ -568,7 +572,8 @@ static enum nb_error nb_op_ys_init_node_infos(struct nb_op_yield_state *ys)
inner = node;
prevlen = 0;
xplen = strlen(xpath);
- darr_free(xpath);
+ darr_free(ys->xpath);
+ ys->xpath = xpath;
for (i = len; i > 0; i--, inner = &inner->parent->node) {
ni = &ys->node_infos[i - 1];
ni->inner = inner;
@@ -897,8 +902,7 @@ static const struct lysc_node *nb_op_sib_first(struct nb_op_yield_state *ys,
* base of the user query, return the next schema node from the query
* string (schema_path).
*/
- if (last != NULL &&
- !CHECK_FLAG(last->schema->nodetype, LYS_CASE | LYS_CHOICE))
+ if (last != NULL)
assert(last->schema == parent);
if (darr_lasti(ys->node_infos) < ys->query_base_level)
return ys->schema_path[darr_lasti(ys->node_infos) + 1];
@@ -975,7 +979,8 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
if (!walk_stem_tip)
return NB_ERR_NOT_FOUND;
- if (ys->schema_path[0]->nodetype == LYS_CHOICE) {
+ if (ys->schema_path[0]->parent &&
+ CHECK_FLAG(ys->schema_path[0]->parent->nodetype, LYS_CHOICE|LYS_CASE)) {
flog_err(EC_LIB_NB_OPERATIONAL_DATA,
"%s: unable to walk root level choice node from module: %s",
__func__, ys->schema_path[0]->module->name);
@@ -1082,8 +1087,12 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER))
xpath_child = nb_op_get_child_path(ys->xpath, sib,
xpath_child);
- else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE))
+ else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE)) {
darr_in_strdup(xpath_child, ys->xpath);
+ len = darr_last(ys->node_infos)->xpath_len;
+ darr_setlen(xpath_child, len + 1);
+ xpath_child[len] = 0;
+ }
nn = sib->priv;
@@ -1703,22 +1712,22 @@ static enum nb_error nb_op_ys_init_schema_path(struct nb_op_yield_state *ys,
* NOTE: appears to be a bug in nb_node linkage where parent can be NULL,
* or I'm misunderstanding the code, in any case we use the libyang
* linkage to walk which works fine.
- *
- * XXX: we don't actually support choice/case yet, they are container
- * types in the libyang schema, but won't be in data so our length
- * checking gets messed up.
*/
- for (sn = nblast->snode, count = 0; sn; count++, sn = sn->parent)
+ for (sn = nblast->snode, count = 0; sn; sn = sn->parent) {
if (sn != nblast->snode)
assert(CHECK_FLAG(sn->nodetype,
- LYS_CONTAINER | LYS_LIST |
- LYS_CHOICE | LYS_CASE));
+ LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE));
+ if (!CHECK_FLAG(sn->nodetype, LYS_CHOICE | LYS_CASE))
+ count++;
+ }
/* create our arrays */
darr_append_n(ys->schema_path, count);
darr_append_n(ys->query_tokens, count);
darr_append_nz(ys->non_specific_predicate, count);
- for (sn = nblast->snode; sn; sn = sn->parent)
- ys->schema_path[--count] = sn;
+ for (sn = nblast->snode; sn; sn = sn->parent) {
+ if (!CHECK_FLAG(sn->nodetype, LYS_CHOICE | LYS_CASE))
+ ys->schema_path[--count] = sn;
+ }
/*
* Now tokenize the query string and get pointers to each token
@@ -1737,50 +1746,42 @@ static enum nb_error nb_op_ys_init_schema_path(struct nb_op_yield_state *ys,
int nlen = strlen(name);
int mnlen = 0;
- /*
- * Technically the query_token for choice/case should probably be pointing at
- * the child (leaf) rather than the parent (container), however,
- * we only use these for processing list nodes so KISS.
- */
- if (CHECK_FLAG(ys->schema_path[i]->nodetype,
- LYS_CASE | LYS_CHOICE)) {
- ys->query_tokens[i] = ys->query_tokens[i - 1];
- continue;
- }
-
+ s2 = s;
while (true) {
- s2 = strstr(s, name);
+ /* skip past any module name prefix */
+ s2 = strstr(s2, name);
if (!s2)
goto error;
- if (s2[-1] == ':') {
+ if (s2 > s && s2[-1] == ':') {
mnlen = strlen(modname) + 1;
- if (ys->query_tokstr > s2 - mnlen ||
- strncmp(s2 - mnlen, modname, mnlen - 1))
- goto error;
+ if (s2 - s < mnlen || strncmp(s2 - mnlen, modname, mnlen - 1)) {
+ /* No match of module prefix, advance and try again */
+ s2 += strlen(name);
+ continue;
+ }
s2 -= mnlen;
nlen += mnlen;
}
- s = s2;
- if ((i == 0 || s[-1] == '/') &&
- (s[nlen] == 0 || s[nlen] == '[' || s[nlen] == '/'))
+ if ((i == 0 || s2[-1] == '/') &&
+ (s2[nlen] == 0 || s2[nlen] == '[' || s2[nlen] == '/')) {
+ s = s2;
break;
- /*
- * Advance past the incorrect match, must have been
- * part of previous predicate.
- */
- s += nlen;
+ }
+ /* No exact match at end, advance and try again */
+ s2 += strlen(name);
}
/* NUL terminate previous token and save this one */
- if (i > 0)
+ if (i > 0) {
+ assert(s[-1] == '/');
s[-1] = 0;
+ }
ys->query_tokens[i] = s;
s += nlen;
}
- /* NOTE: need to subtract choice/case nodes when these are supported */
ys->query_base_level = darr_lasti(ys->schema_path);
return NB_OK;
diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c
index dc077dbbd6..d3f3517efd 100644
--- a/pimd/pim_autorp.c
+++ b/pimd/pim_autorp.c
@@ -967,6 +967,7 @@ err:
static bool pim_autorp_socket_enable(struct pim_autorp *autorp)
{
int fd;
+ struct interface *ifp;
/* Return early if socket is already enabled */
if (autorp->sock != -1)
@@ -980,6 +981,13 @@ static bool pim_autorp_socket_enable(struct pim_autorp *autorp)
return false;
}
+ if (vrf_bind(autorp->pim->vrf->vrf_id, fd, NULL)) {
+ zlog_warn("Could not bind autorp socket to vrf fd=%d: vrf_id=%d: errno=%d: %s",
+ fd, autorp->pim->vrf->vrf_id, errno, safe_strerror(errno));
+ close(fd);
+ return false;
+ }
+
if (!pim_autorp_setup(fd)) {
zlog_warn("Could not setup autorp socket fd=%d: errno=%d: %s", fd, errno,
safe_strerror(errno));
@@ -990,6 +998,11 @@ static bool pim_autorp_socket_enable(struct pim_autorp *autorp)
autorp->sock = fd;
+ /* Join autorp groups on all pim enabled interfaces in the VRF */
+ FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) {
+ pim_autorp_add_ifp(ifp);
+ }
+
if (PIM_DEBUG_AUTORP)
zlog_debug("%s: AutoRP socket enabled (fd=%u)", __func__, fd);
@@ -1002,6 +1015,7 @@ static bool pim_autorp_socket_disable(struct pim_autorp *autorp)
if (autorp->sock == -1)
return true;
+ /* No need to leave the autorp groups explicitly, they are left when the socket is closed */
if (close(autorp->sock)) {
zlog_warn("Failure closing autorp socket: fd=%d errno=%d: %s", autorp->sock, errno,
safe_strerror(errno));
@@ -1428,10 +1442,10 @@ void pim_autorp_add_ifp(struct interface *ifp)
{
/* Add a new interface for autorp
* When autorp is enabled, we must join the autorp groups on all
- * pim/multicast interfaces. When autorp first starts, if finds all
- * current multicast interfaces and joins on them. If a new interface
- * comes up or is configured for multicast after autorp is running, then
- * this method will add it for autorp->
+ * pim/multicast interfaces. When autorp becomes enabled, it finds all
+ * current pim enabled interfaces and joins the autorp groups on them.
+ * Any new interfaces added after autorp is enabled will use this function
+ * to join the autorp groups
* This is called even when adding a new pim interface that is not yet
* active, so make sure the check, it'll call in again once the interface is up.
*/
@@ -1441,7 +1455,8 @@ void pim_autorp_add_ifp(struct interface *ifp)
pim_ifp = ifp->info;
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp && pim_ifp->pim_enable) {
pim = pim_ifp->pim;
- if (pim && pim->autorp && pim->autorp->do_discovery) {
+ if (pim && pim->autorp &&
+ (pim->autorp->do_discovery || pim->autorp->send_rp_discovery)) {
if (PIM_DEBUG_AUTORP)
zlog_debug("%s: Adding interface %s to AutoRP, joining AutoRP groups",
__func__, ifp->name);
@@ -1477,44 +1492,37 @@ void pim_autorp_rm_ifp(struct interface *ifp)
void pim_autorp_start_discovery(struct pim_instance *pim)
{
- struct interface *ifp;
struct pim_autorp *autorp = pim->autorp;
+ if (autorp->do_discovery)
+ return;
+
+ autorp->do_discovery = true;
+
/* Make sure the socket is open and ready */
if (!pim_autorp_socket_enable(autorp)) {
zlog_err("%s: AutoRP failed to open socket", __func__);
return;
}
- if (!autorp->do_discovery) {
- autorp->do_discovery = true;
- autorp_read_on(autorp);
-
- FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) {
- pim_autorp_add_ifp(ifp);
- }
+ autorp_read_on(autorp);
- if (PIM_DEBUG_AUTORP)
- zlog_debug("%s: AutoRP Discovery started", __func__);
- }
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP Discovery started", __func__);
}
void pim_autorp_stop_discovery(struct pim_instance *pim)
{
- struct interface *ifp;
struct pim_autorp *autorp = pim->autorp;
- if (autorp->do_discovery) {
- FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) {
- pim_autorp_rm_ifp(ifp);
- }
+ if (!autorp->do_discovery)
+ return;
- autorp->do_discovery = false;
- autorp_read_off(autorp);
+ autorp->do_discovery = false;
+ autorp_read_off(autorp);
- if (PIM_DEBUG_AUTORP)
- zlog_debug("%s: AutoRP Discovery stopped", __func__);
- }
+ if (PIM_DEBUG_AUTORP)
+ zlog_debug("%s: AutoRP Discovery stopped", __func__);
/* Close the socket if we need to */
if (pim_autorp_should_close(autorp) && !pim_autorp_socket_disable(autorp))
@@ -1549,7 +1557,10 @@ void pim_autorp_init(struct pim_instance *pim)
if (PIM_DEBUG_AUTORP)
zlog_debug("%s: AutoRP Initialized", __func__);
+}
+void pim_autorp_enable(struct pim_instance *pim)
+{
/* Start AutoRP discovery by default on startup */
pim_autorp_start_discovery(pim);
}
diff --git a/pimd/pim_autorp.h b/pimd/pim_autorp.h
index e4c6530109..88aebe5b7d 100644
--- a/pimd/pim_autorp.h
+++ b/pimd/pim_autorp.h
@@ -173,6 +173,7 @@ void pim_autorp_rm_ifp(struct interface *ifp);
void pim_autorp_start_discovery(struct pim_instance *pim);
void pim_autorp_stop_discovery(struct pim_instance *pim);
void pim_autorp_init(struct pim_instance *pim);
+void pim_autorp_enable(struct pim_instance *pim);
void pim_autorp_finish(struct pim_instance *pim);
int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty);
void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim, const char *component,
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 9316cebc0a..6d0f2798f9 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -1898,9 +1898,7 @@ static int pim_ifp_up(struct interface *ifp)
}
#if PIM_IPV == 4
- if (pim->autorp && pim->autorp->do_discovery && pim_ifp &&
- pim_ifp->pim_enable)
- pim_autorp_add_ifp(ifp);
+ pim_autorp_add_ifp(ifp);
#endif
pim_cand_addrs_changed();
@@ -2017,8 +2015,7 @@ void pim_pim_interface_delete(struct interface *ifp)
return;
#if PIM_IPV == 4
- if (pim_ifp->pim_enable)
- pim_autorp_rm_ifp(ifp);
+ pim_autorp_rm_ifp(ifp);
#endif
pim_ifp->pim_enable = false;
diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c
index 3945c5923d..f64b02e44d 100644
--- a/pimd/pim_instance.c
+++ b/pimd/pim_instance.c
@@ -181,8 +181,15 @@ static int pim_vrf_enable(struct vrf *vrf)
zlog_debug("%s: for %s %u", __func__, vrf->name, vrf->vrf_id);
+ if (vrf_bind(vrf->vrf_id, pim->reg_sock, NULL) < 0)
+ zlog_warn("Failed to bind register socket to VRF %s", vrf->name);
+
pim_mroute_socket_enable(pim);
+#if PIM_IPV == 4
+ pim_autorp_enable(pim);
+#endif
+
FOR_ALL_INTERFACES (vrf, ifp) {
if (!ifp->info)
continue;
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 6c13e1324f..30daa3a929 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -876,17 +876,11 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
pim->vrf->name);
#endif
-#ifdef SO_BINDTODEVICE
- if (pim->vrf->vrf_id != VRF_DEFAULT
- && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
- pim->vrf->name, strlen(pim->vrf->name))) {
- zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
- safe_strerror(errno));
+ if (vrf_bind(pim->vrf->vrf_id, fd, NULL)) {
+ zlog_warn("Could not bind to vrf: %s", safe_strerror(errno));
close(fd);
return -3;
}
-#endif
-
}
pim->mroute_socket = fd;
diff --git a/tests/lib/northbound/test_oper_data.in b/tests/lib/northbound/test_oper_data.in
index 0053148953..94fcdc1e1c 100644
--- a/tests/lib/northbound/test_oper_data.in
+++ b/tests/lib/northbound/test_oper_data.in
@@ -2,4 +2,8 @@ show yang operational-data /frr-test-module:frr-test-module
show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[2]
show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[3]/interface
show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
+show yang operational-data /frr-test-module:frr-test-module/c1value
+show yang operational-data /frr-test-module:frr-test-module/c2cont
+show yang operational-data /frr-test-module:frr-test-module/c2cont/
+show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
test rpc
diff --git a/tests/lib/northbound/test_oper_data.refout b/tests/lib/northbound/test_oper_data.refout
index 2536e0306b..57061d0371 100644
--- a/tests/lib/northbound/test_oper_data.refout
+++ b/tests/lib/northbound/test_oper_data.refout
@@ -174,6 +174,36 @@ test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name=
}
test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
{}
+test# show yang operational-data /frr-test-module:frr-test-module/c1value
+{
+ "frr-test-module:frr-test-module": {
+ "c1value": 21
+ }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/c2cont
+{
+ "frr-test-module:frr-test-module": {
+ "c2cont": {
+ "c2value": 2868969987
+ }
+ }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/c2cont/
+{
+ "frr-test-module:frr-test-module": {
+ "c2cont": {
+ "c2value": 2868969987
+ }
+ }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
+{
+ "frr-test-module:frr-test-module": {
+ "c2cont": {
+ "c2value": 2868969987
+ }
+ }
+}
test# test rpc
vrf testname data testdata
test#
diff --git a/tests/topotests/pim_autorp/test_pim_autorp.py b/tests/topotests/pim_autorp/test_pim_autorp.py
index 61cf8ebbc5..5edf1db6af 100644
--- a/tests/topotests/pim_autorp/test_pim_autorp.py
+++ b/tests/topotests/pim_autorp/test_pim_autorp.py
@@ -158,6 +158,103 @@ def test_pim_autorp_init(request):
)
+def test_pim_autorp_disable_enable(request):
+ "Test PIM AutoRP disable and re-enable works properly"
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Ensure AutoRP groups are joined on all routers")
+ for rtr in ["r1", "r2", "r3", "r4"]:
+ expected = {
+ f"{rtr}-eth0": {
+ "name": f"{rtr}-eth0",
+ "224.0.1.39": "*",
+ "224.0.1.40": "*",
+ },
+ f"{rtr}-eth1": {
+ "name": f"{rtr}-eth1",
+ "224.0.1.39": "*",
+ "224.0.1.40": "*",
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[rtr],
+ "show ip igmp sources json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None)
+ assert result is None, "{} does not have correct autorp groups joined".format(
+ rtr
+ )
+
+ step("Disable AutoRP on all routers")
+ for rtr in ["r1", "r2", "r3", "r4"]:
+ tgen.routers()[rtr].vtysh_cmd(
+ """
+ conf
+ router pim
+ no autorp discovery
+ """
+ )
+
+ step("Ensure AutoRP groups are no longer joined on all routers")
+ for rtr in ["r1", "r2", "r3", "r4"]:
+ expected = {f"{rtr}-eth0": None, f"{rtr}-eth1": None}
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[rtr],
+ "show ip igmp sources json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None)
+ assert result is None, "{} does not have correct autorp groups joined".format(
+ rtr
+ )
+
+ step("Re-enable AutoRP on all routers")
+ for rtr in ["r1", "r2", "r3", "r4"]:
+ tgen.routers()[rtr].vtysh_cmd(
+ """
+ conf
+ router pim
+ autorp discovery
+ """
+ )
+
+ step("Ensure AutoRP groups are re-joined on all routers")
+ for rtr in ["r1", "r2", "r3", "r4"]:
+ expected = {
+ f"{rtr}-eth0": {
+ "name": f"{rtr}-eth0",
+ "224.0.1.39": "*",
+ "224.0.1.40": "*",
+ },
+ f"{rtr}-eth1": {
+ "name": f"{rtr}-eth1",
+ "224.0.1.39": "*",
+ "224.0.1.40": "*",
+ },
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[rtr],
+ "show ip igmp sources json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None)
+ assert result is None, "{} does not have correct autorp groups joined".format(
+ rtr
+ )
+
+
def test_pim_autorp_no_mapping_agent_rp(request):
"Test PIM AutoRP candidate with no mapping agent"
tgen = get_topogen()