mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 10:09:25 +00:00
Merge pull request #8561 from opensourcerouting/msdp-refactor-v2
pimd: rework MSDP mesh groups
This commit is contained in:
commit
59ec133a03
489
pimd/pim_cmd.c
489
pimd/pim_cmd.c
@ -3853,6 +3853,54 @@ static const char *pim_cli_get_vrf_name(struct vty *vty)
|
||||
return yang_dnode_get_string(vrf_node, "./name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility function to keep the legacy mesh group CLI behavior:
|
||||
* Delete group when there are no more configurations in it.
|
||||
*
|
||||
* NOTE:
|
||||
* Don't forget to call `nb_cli_apply_changes` after this.
|
||||
*/
|
||||
static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
|
||||
const char *gname)
|
||||
{
|
||||
const char *vrfname;
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
char xpath_member_value[XPATH_MAXLEN];
|
||||
const struct lyd_node *member_dnode;
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return;
|
||||
|
||||
/* Get mesh group base XPath. */
|
||||
snprintf(xpath_value, sizeof(xpath_value),
|
||||
FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
|
||||
/* Group must exists, otherwise just quit. */
|
||||
if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
|
||||
return;
|
||||
|
||||
/* Group members check: */
|
||||
strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
|
||||
strlcat(xpath_member_value, "/members", sizeof(xpath_member_value));
|
||||
if (yang_dnode_exists(vty->candidate_config->dnode,
|
||||
xpath_member_value)) {
|
||||
member_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
||||
xpath_member_value);
|
||||
if (!yang_is_last_list_dnode(member_dnode))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Source address check: */
|
||||
strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
|
||||
strlcat(xpath_member_value, "/source", sizeof(xpath_member_value));
|
||||
if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value))
|
||||
return;
|
||||
|
||||
/* No configurations found: delete it. */
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
|
||||
}
|
||||
|
||||
DEFUN (clear_ip_interfaces,
|
||||
clear_ip_interfaces_cmd,
|
||||
"clear ip interfaces [vrf NAME]",
|
||||
@ -9685,305 +9733,199 @@ DEFUN (no_ip_msdp_peer,
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFUN (ip_msdp_mesh_group_member,
|
||||
ip_msdp_mesh_group_member_cmd,
|
||||
"ip msdp mesh-group WORD member A.B.C.D",
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Configure MSDP mesh-group\n"
|
||||
"mesh group name\n"
|
||||
"mesh group member\n"
|
||||
"peer ip address\n")
|
||||
DEFPY(ip_msdp_mesh_group_member,
|
||||
ip_msdp_mesh_group_member_cmd,
|
||||
"ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Configure MSDP mesh-group\n"
|
||||
"Mesh group name\n"
|
||||
"Mesh group member\n"
|
||||
"Peer IP address\n")
|
||||
{
|
||||
const char *vrfname;
|
||||
char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
|
||||
char msdp_mesh_group_member_xpath[XPATH_MAXLEN];
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
|
||||
sizeof(msdp_mesh_group_name_xpath));
|
||||
snprintf(msdp_mesh_group_member_xpath,
|
||||
sizeof(msdp_mesh_group_member_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(msdp_mesh_group_member_xpath, "/msdp-mesh-group/member-ip",
|
||||
sizeof(msdp_mesh_group_member_xpath));
|
||||
/* Create mesh group. */
|
||||
snprintf(xpath_value, sizeof(xpath_value),
|
||||
FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
|
||||
|
||||
nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
|
||||
argv[3]->arg);
|
||||
nb_cli_enqueue_change(vty, msdp_mesh_group_member_xpath, NB_OP_CREATE,
|
||||
argv[5]->arg);
|
||||
/* Create mesh group member. */
|
||||
strlcat(xpath_value, "/members[address='", sizeof(xpath_value));
|
||||
strlcat(xpath_value, maddr_str, sizeof(xpath_value));
|
||||
strlcat(xpath_value, "']", sizeof(xpath_value));
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFUN (no_ip_msdp_mesh_group_member,
|
||||
no_ip_msdp_mesh_group_member_cmd,
|
||||
"no ip msdp mesh-group WORD member A.B.C.D",
|
||||
NO_STR
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Delete MSDP mesh-group member\n"
|
||||
"mesh group name\n"
|
||||
"mesh group member\n"
|
||||
"peer ip address\n")
|
||||
DEFPY(no_ip_msdp_mesh_group_member,
|
||||
no_ip_msdp_mesh_group_member_cmd,
|
||||
"no ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
|
||||
NO_STR
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Delete MSDP mesh-group member\n"
|
||||
"Mesh group name\n"
|
||||
"Mesh group member\n"
|
||||
"Peer IP address\n")
|
||||
{
|
||||
const char *vrfname;
|
||||
char pim_af_xpath[XPATH_MAXLEN];
|
||||
char mesh_group_xpath[XPATH_MAXLEN + 32];
|
||||
char group_member_list_xpath[XPATH_MAXLEN + 64];
|
||||
char group_member_xpath[XPATH_MAXLEN + 128];
|
||||
char source_xpath[XPATH_MAXLEN + 64];
|
||||
char mesh_group_name_xpath[XPATH_MAXLEN + 64];
|
||||
const char *mesh_group_name;
|
||||
const struct lyd_node *member_dnode;
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
char xpath_member_value[XPATH_MAXLEN];
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
snprintf(pim_af_xpath, sizeof(pim_af_xpath), FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
/* Get mesh group base XPath. */
|
||||
snprintf(xpath_value, sizeof(xpath_value),
|
||||
FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
|
||||
|
||||
snprintf(mesh_group_xpath, sizeof(mesh_group_xpath),
|
||||
"%s/msdp-mesh-group", pim_af_xpath);
|
||||
|
||||
snprintf(group_member_list_xpath, sizeof(group_member_list_xpath),
|
||||
"%s/msdp-mesh-group/member-ip", pim_af_xpath);
|
||||
|
||||
snprintf(group_member_xpath, sizeof(group_member_xpath), "%s[.='%s']",
|
||||
group_member_list_xpath, argv[6]->arg);
|
||||
|
||||
snprintf(source_xpath, sizeof(source_xpath),
|
||||
"%s/msdp-mesh-group/source-ip", pim_af_xpath);
|
||||
|
||||
snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
|
||||
"%s/msdp-mesh-group/mesh-group-name", pim_af_xpath);
|
||||
|
||||
if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
|
||||
== true) {
|
||||
mesh_group_name = yang_dnode_get_string(running_config->dnode,
|
||||
mesh_group_name_xpath);
|
||||
if (strcmp(mesh_group_name, argv[4]->arg)) {
|
||||
vty_out(vty, "%% mesh-group does not exist\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (yang_dnode_exists(vty->candidate_config->dnode,
|
||||
group_member_xpath)) {
|
||||
if (!yang_dnode_exists(vty->candidate_config->dnode,
|
||||
source_xpath)) {
|
||||
member_dnode = yang_dnode_get(
|
||||
vty->candidate_config->dnode,
|
||||
group_member_xpath);
|
||||
if (yang_is_last_list_dnode(member_dnode)) {
|
||||
nb_cli_enqueue_change(vty, mesh_group_xpath,
|
||||
NB_OP_DESTROY, NULL);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
nb_cli_enqueue_change(vty, group_member_list_xpath,
|
||||
NB_OP_DESTROY, argv[6]->arg);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
nb_cli_enqueue_change(vty, group_member_list_xpath,
|
||||
NB_OP_DESTROY, argv[6]->arg);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
vty_out(vty, "%% mesh-group member does not exist\n");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (ip_msdp_mesh_group_source,
|
||||
ip_msdp_mesh_group_source_cmd,
|
||||
"ip msdp mesh-group WORD source A.B.C.D",
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Configure MSDP mesh-group\n"
|
||||
"mesh group name\n"
|
||||
"mesh group local address\n"
|
||||
"source ip address for the TCP connection\n")
|
||||
{
|
||||
const char *vrfname;
|
||||
char msdp_mesh_source_ip_xpath[XPATH_MAXLEN];
|
||||
char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) {
|
||||
vty_out(vty, "%% mesh-group does not exist\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
|
||||
sizeof(msdp_mesh_group_name_xpath));
|
||||
|
||||
snprintf(msdp_mesh_source_ip_xpath, sizeof(msdp_mesh_source_ip_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(msdp_mesh_source_ip_xpath, "/msdp-mesh-group/source-ip",
|
||||
sizeof(msdp_mesh_source_ip_xpath));
|
||||
|
||||
nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
|
||||
argv[3]->arg);
|
||||
nb_cli_enqueue_change(vty, msdp_mesh_source_ip_xpath, NB_OP_MODIFY,
|
||||
argv[5]->arg);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFUN (no_ip_msdp_mesh_group_source,
|
||||
no_ip_msdp_mesh_group_source_cmd,
|
||||
"no ip msdp mesh-group WORD source [A.B.C.D]",
|
||||
NO_STR
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Delete MSDP mesh-group source\n"
|
||||
"mesh group name\n"
|
||||
"mesh group source\n"
|
||||
"mesh group local address\n")
|
||||
{
|
||||
const char *vrfname;
|
||||
char msdp_mesh_xpath[XPATH_MAXLEN];
|
||||
char source_xpath[XPATH_MAXLEN];
|
||||
char group_member_xpath[XPATH_MAXLEN];
|
||||
char mesh_group_name_xpath[XPATH_MAXLEN];
|
||||
const char *mesh_group_name;
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
|
||||
|
||||
snprintf(source_xpath, sizeof(source_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(source_xpath, "/msdp-mesh-group/source-ip",
|
||||
sizeof(source_xpath));
|
||||
|
||||
snprintf(group_member_xpath,
|
||||
sizeof(group_member_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(group_member_xpath, "/msdp-mesh-group/member-ip",
|
||||
sizeof(group_member_xpath));
|
||||
|
||||
snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
|
||||
sizeof(mesh_group_name_xpath));
|
||||
|
||||
if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
|
||||
== true) {
|
||||
mesh_group_name = yang_dnode_get_string(running_config->dnode,
|
||||
mesh_group_name_xpath);
|
||||
if (strcmp(mesh_group_name, argv[4]->arg)) {
|
||||
vty_out(vty, "%% mesh-group does not exist\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove mesh group member. */
|
||||
strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
|
||||
strlcat(xpath_member_value, "/members[address='",
|
||||
sizeof(xpath_member_value));
|
||||
strlcat(xpath_member_value, maddr_str, sizeof(xpath_member_value));
|
||||
strlcat(xpath_member_value, "']", sizeof(xpath_member_value));
|
||||
if (!yang_dnode_exists(vty->candidate_config->dnode,
|
||||
group_member_xpath)) {
|
||||
nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY,
|
||||
NULL);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
xpath_member_value)) {
|
||||
vty_out(vty, "%% mesh-group member does not exist\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
nb_cli_enqueue_change(vty, source_xpath, NB_OP_DESTROY, NULL);
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
|
||||
|
||||
/*
|
||||
* If this is the last member, then we must remove the group altogether
|
||||
* to not break legacy CLI behaviour.
|
||||
*/
|
||||
pim_cli_legacy_mesh_group_behavior(vty, gname);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFUN (no_ip_msdp_mesh_group,
|
||||
no_ip_msdp_mesh_group_cmd,
|
||||
"no ip msdp mesh-group [WORD]",
|
||||
NO_STR
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Delete MSDP mesh-group\n"
|
||||
"mesh group name")
|
||||
DEFPY(ip_msdp_mesh_group_source,
|
||||
ip_msdp_mesh_group_source_cmd,
|
||||
"ip msdp mesh-group WORD$gname source A.B.C.D$saddr",
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Configure MSDP mesh-group\n"
|
||||
"Mesh group name\n"
|
||||
"Mesh group local address\n"
|
||||
"Source IP address for the TCP connection\n")
|
||||
{
|
||||
const char *vrfname;
|
||||
const char *mesh_group_name;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
char msdp_mesh_xpath[XPATH_MAXLEN];
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
if (argc == 5) {
|
||||
snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd",
|
||||
"pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(xpath, "/msdp-mesh-group/mesh-group-name",
|
||||
sizeof(xpath));
|
||||
/* Create mesh group. */
|
||||
snprintf(xpath_value, sizeof(xpath_value),
|
||||
FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
|
||||
|
||||
if (yang_dnode_exists(running_config->dnode, xpath) == true) {
|
||||
mesh_group_name =
|
||||
yang_dnode_get_string(running_config->dnode,
|
||||
xpath);
|
||||
/* Create mesh group member. */
|
||||
strlcat(xpath_value, "/source", sizeof(xpath_value));
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str);
|
||||
|
||||
if (strcmp(mesh_group_name, argv[4]->arg)) {
|
||||
vty_out(vty, "%% mesh-group does not exist\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
|
||||
FRR_PIM_AF_XPATH,
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
||||
strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
|
||||
|
||||
nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, NULL);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
static void print_empty_json_obj(struct vty *vty)
|
||||
DEFPY(no_ip_msdp_mesh_group_source,
|
||||
no_ip_msdp_mesh_group_source_cmd,
|
||||
"no ip msdp mesh-group WORD$gname source [A.B.C.D]",
|
||||
NO_STR
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Delete MSDP mesh-group source\n"
|
||||
"Mesh group name\n"
|
||||
"Mesh group source\n"
|
||||
"Mesh group local address\n")
|
||||
{
|
||||
json_object *json;
|
||||
json = json_object_new_object();
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
const char *vrfname;
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
/* Get mesh group base XPath. */
|
||||
snprintf(xpath_value, sizeof(xpath_value),
|
||||
FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
|
||||
|
||||
/* Create mesh group member. */
|
||||
strlcat(xpath_value, "/source", sizeof(xpath_value));
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
|
||||
|
||||
/*
|
||||
* If this is the last member, then we must remove the group altogether
|
||||
* to not break legacy CLI behaviour.
|
||||
*/
|
||||
pim_cli_legacy_mesh_group_behavior(vty, gname);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
|
||||
bool uj)
|
||||
DEFPY(no_ip_msdp_mesh_group,
|
||||
no_ip_msdp_mesh_group_cmd,
|
||||
"no ip msdp mesh-group WORD$gname",
|
||||
NO_STR
|
||||
IP_STR
|
||||
CFG_MSDP_STR
|
||||
"Delete MSDP mesh-group\n"
|
||||
"Mesh group name")
|
||||
{
|
||||
const char *vrfname;
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
|
||||
vrfname = pim_cli_get_vrf_name(vty);
|
||||
if (vrfname == NULL)
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
/* Get mesh group base XPath. */
|
||||
snprintf(xpath_value, sizeof(xpath_value),
|
||||
FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
|
||||
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
|
||||
if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
|
||||
return CMD_SUCCESS;
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg,
|
||||
struct json_object *json)
|
||||
{
|
||||
struct listnode *mbrnode;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
char mbr_str[INET_ADDRSTRLEN];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
char state_str[PIM_MSDP_STATE_STRLEN];
|
||||
enum pim_msdp_peer_state state;
|
||||
json_object *json = NULL;
|
||||
json_object *json_mg_row = NULL;
|
||||
json_object *json_members = NULL;
|
||||
json_object *json_row = NULL;
|
||||
|
||||
if (!mg) {
|
||||
if (uj)
|
||||
print_empty_json_obj(vty);
|
||||
return;
|
||||
}
|
||||
|
||||
pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str));
|
||||
if (uj) {
|
||||
json = json_object_new_object();
|
||||
if (json) {
|
||||
/* currently there is only one mesh group but we should still
|
||||
* make
|
||||
* it a dict with mg-name as key */
|
||||
@ -10005,7 +9947,7 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
|
||||
state = PIM_MSDP_DISABLED;
|
||||
}
|
||||
pim_msdp_state_dump(state, state_str, sizeof(state_str));
|
||||
if (uj) {
|
||||
if (json) {
|
||||
json_row = json_object_new_object();
|
||||
json_object_string_add(json_row, "member", mbr_str);
|
||||
json_object_string_add(json_row, "state", state_str);
|
||||
@ -10020,12 +9962,8 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
|
||||
}
|
||||
}
|
||||
|
||||
if (uj) {
|
||||
if (json)
|
||||
json_object_object_add(json, mg->mesh_group_name, json_mg_row);
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN (show_ip_msdp_mesh_group,
|
||||
@ -10040,12 +9978,34 @@ DEFUN (show_ip_msdp_mesh_group,
|
||||
{
|
||||
bool uj = use_json(argc, argv);
|
||||
int idx = 2;
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
||||
struct pim_instance *pim = vrf->info;
|
||||
struct json_object *json = NULL;
|
||||
|
||||
if (!vrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
ip_msdp_show_mesh_group(vrf->info, vty, uj);
|
||||
/* Quick case: list is empty. */
|
||||
if (SLIST_EMPTY(&pim->msdp.mglist)) {
|
||||
if (uj)
|
||||
vty_out(vty, "{}\n");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
|
||||
ip_msdp_show_mesh_group(vty, mg, json);
|
||||
|
||||
if (uj) {
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -10061,23 +10021,32 @@ DEFUN (show_ip_msdp_mesh_group_vrf_all,
|
||||
JSON_STR)
|
||||
{
|
||||
bool uj = use_json(argc, argv);
|
||||
struct json_object *json = NULL, *vrf_json = NULL;
|
||||
struct pim_instance *pim;
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf;
|
||||
bool first = true;
|
||||
|
||||
if (uj)
|
||||
vty_out(vty, "{ ");
|
||||
json = json_object_new_object();
|
||||
|
||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||
if (uj) {
|
||||
if (!first)
|
||||
vty_out(vty, ", ");
|
||||
vty_out(vty, " \"%s\": ", vrf->name);
|
||||
first = false;
|
||||
vrf_json = json_object_new_object();
|
||||
json_object_object_add(json, vrf->name, vrf_json);
|
||||
} else
|
||||
vty_out(vty, "VRF: %s\n", vrf->name);
|
||||
ip_msdp_show_mesh_group(vrf->info, vty, uj);
|
||||
|
||||
pim = vrf->info;
|
||||
SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
|
||||
ip_msdp_show_mesh_group(vty, mg, vrf_json);
|
||||
}
|
||||
|
||||
if (uj) {
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
if (uj)
|
||||
vty_out(vty, "}\n");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
318
pimd/pim_msdp.c
318
pimd/pim_msdp.c
@ -58,8 +58,6 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa,
|
||||
enum pim_msdp_sa_flags flags);
|
||||
static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2);
|
||||
static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr);
|
||||
static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
|
||||
struct pim_msdp_mg_mbr *mbr);
|
||||
|
||||
/************************ SA cache management ******************************/
|
||||
static void pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa,
|
||||
@ -1252,27 +1250,33 @@ static int pim_msdp_peer_comp(const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
/************************** Mesh group management **************************/
|
||||
static void pim_msdp_mg_free(struct pim_instance *pim)
|
||||
void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg **mgp)
|
||||
{
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct listnode *n, *nn;
|
||||
|
||||
/* If the mesh-group has valid member or src_ip don't delete it */
|
||||
if (!mg || mg->mbr_cnt || (mg->src_ip.s_addr != INADDR_ANY)) {
|
||||
if (*mgp == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* SIP is being removed - tear down all active peer sessions */
|
||||
for (ALL_LIST_ELEMENTS((*mgp)->mbr_list, n, nn, mbr))
|
||||
pim_msdp_mg_mbr_del((*mgp), mbr);
|
||||
|
||||
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||
zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name);
|
||||
zlog_debug("MSDP mesh-group %s deleted",
|
||||
(*mgp)->mesh_group_name);
|
||||
}
|
||||
XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
|
||||
|
||||
if (mg->mbr_list)
|
||||
list_delete(&mg->mbr_list);
|
||||
XFREE(MTYPE_PIM_MSDP_MG_NAME, (*mgp)->mesh_group_name);
|
||||
|
||||
XFREE(MTYPE_PIM_MSDP_MG, pim->msdp.mg);
|
||||
if ((*mgp)->mbr_list)
|
||||
list_delete(&(*mgp)->mbr_list);
|
||||
|
||||
XFREE(MTYPE_PIM_MSDP_MG, (*mgp));
|
||||
}
|
||||
|
||||
static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
|
||||
struct pim_msdp_mg *pim_msdp_mg_new(struct pim_instance *pim,
|
||||
const char *mesh_group_name)
|
||||
{
|
||||
struct pim_msdp_mg *mg;
|
||||
|
||||
@ -1286,54 +1290,12 @@ static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
|
||||
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||
zlog_debug("MSDP mesh-group %s created", mg->mesh_group_name);
|
||||
}
|
||||
|
||||
SLIST_INSERT_HEAD(&pim->msdp.mglist, mg, mg_entry);
|
||||
|
||||
return mg;
|
||||
}
|
||||
|
||||
enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
|
||||
const char *mesh_group_name)
|
||||
{
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
|
||||
if (!mg
|
||||
|| (mesh_group_name
|
||||
&& strcmp(mg->mesh_group_name, mesh_group_name))) {
|
||||
return PIM_MSDP_ERR_NO_MG;
|
||||
}
|
||||
|
||||
/* delete all the mesh-group members */
|
||||
while (!list_isempty(mg->mbr_list)) {
|
||||
mbr = listnode_head(mg->mbr_list);
|
||||
pim_msdp_mg_mbr_do_del(mg, mbr);
|
||||
}
|
||||
|
||||
/* clear src ip */
|
||||
mg->src_ip.s_addr = INADDR_ANY;
|
||||
|
||||
/* free up the mesh-group */
|
||||
pim_msdp_mg_free(pim);
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
static enum pim_msdp_err pim_msdp_mg_add(struct pim_instance *pim,
|
||||
const char *mesh_group_name)
|
||||
{
|
||||
if (pim->msdp.mg) {
|
||||
if (!strcmp(pim->msdp.mg->mesh_group_name, mesh_group_name)) {
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
/* currently only one mesh-group can exist at a time */
|
||||
return PIM_MSDP_ERR_MAX_MESH_GROUPS;
|
||||
}
|
||||
|
||||
pim->msdp.mg = pim_msdp_mg_new(mesh_group_name);
|
||||
if (!pim->msdp.mg) {
|
||||
return PIM_MSDP_ERR_OOM;
|
||||
}
|
||||
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct pim_msdp_mg_mbr *mbr1 = p1;
|
||||
@ -1353,66 +1315,7 @@ static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr)
|
||||
XFREE(MTYPE_PIM_MSDP_MG_MBR, mbr);
|
||||
}
|
||||
|
||||
static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct pim_instance *pim,
|
||||
struct in_addr mbr_ip)
|
||||
{
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct listnode *mbr_node;
|
||||
|
||||
if (!pim->msdp.mg) {
|
||||
return NULL;
|
||||
}
|
||||
/* we can move this to a hash but considering that number of peers in
|
||||
* a mesh-group that seems like bit of an overkill */
|
||||
for (ALL_LIST_ELEMENTS_RO(pim->msdp.mg->mbr_list, mbr_node, mbr)) {
|
||||
if (mbr->mbr_ip.s_addr == mbr_ip.s_addr) {
|
||||
return mbr;
|
||||
}
|
||||
}
|
||||
return mbr;
|
||||
}
|
||||
|
||||
enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
|
||||
const char *mesh_group_name,
|
||||
struct in_addr mbr_ip)
|
||||
{
|
||||
int rc;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct pim_msdp_mg *mg;
|
||||
|
||||
rc = pim_msdp_mg_add(pim, mesh_group_name);
|
||||
if (rc != PIM_MSDP_ERR_NONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
mg = pim->msdp.mg;
|
||||
mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
|
||||
if (mbr) {
|
||||
return PIM_MSDP_ERR_MG_MBR_EXISTS;
|
||||
}
|
||||
|
||||
mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
|
||||
mbr->mbr_ip = mbr_ip;
|
||||
listnode_add_sort(mg->mbr_list, mbr);
|
||||
|
||||
/* if valid SIP has been configured add peer session */
|
||||
if (mg->src_ip.s_addr != INADDR_ANY) {
|
||||
pim_msdp_peer_add(pim, mbr_ip, mg->src_ip, mesh_group_name,
|
||||
&mbr->mp);
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||
char ip_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<mbr?>", mbr->mbr_ip, ip_str, sizeof(ip_str));
|
||||
zlog_debug("MSDP mesh-group %s mbr %s created",
|
||||
mg->mesh_group_name, ip_str);
|
||||
}
|
||||
++mg->mbr_cnt;
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
|
||||
struct pim_msdp_mg_mbr *mbr)
|
||||
void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr)
|
||||
{
|
||||
/* Delete active peer session if any */
|
||||
if (mbr->mp) {
|
||||
@ -1432,34 +1335,10 @@ static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
|
||||
}
|
||||
}
|
||||
|
||||
enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
|
||||
const char *mesh_group_name,
|
||||
struct in_addr mbr_ip)
|
||||
{
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
|
||||
if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
|
||||
return PIM_MSDP_ERR_NO_MG;
|
||||
}
|
||||
|
||||
mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
|
||||
if (!mbr) {
|
||||
return PIM_MSDP_ERR_NO_MG_MBR;
|
||||
}
|
||||
|
||||
pim_msdp_mg_mbr_do_del(mg, mbr);
|
||||
/* if there are no references to the mg free it */
|
||||
pim_msdp_mg_free(pim);
|
||||
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
|
||||
static void pim_msdp_src_del(struct pim_msdp_mg *mg)
|
||||
{
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct listnode *mbr_node;
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
|
||||
/* SIP is being removed - tear down all active peer sessions */
|
||||
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
|
||||
@ -1474,91 +1353,38 @@ static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
|
||||
}
|
||||
}
|
||||
|
||||
enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
|
||||
const char *mesh_group_name)
|
||||
{
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
|
||||
if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
|
||||
return PIM_MSDP_ERR_NO_MG;
|
||||
}
|
||||
|
||||
if (mg->src_ip.s_addr != INADDR_ANY) {
|
||||
mg->src_ip.s_addr = INADDR_ANY;
|
||||
pim_msdp_mg_src_do_del(pim);
|
||||
/* if there are no references to the mg free it */
|
||||
pim_msdp_mg_free(pim);
|
||||
}
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
|
||||
const char *mesh_group_name,
|
||||
struct in_addr src_ip)
|
||||
{
|
||||
int rc;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct listnode *mbr_node;
|
||||
struct pim_msdp_mg *mg;
|
||||
|
||||
if (src_ip.s_addr == INADDR_ANY) {
|
||||
pim_msdp_mg_src_del(pim, mesh_group_name);
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
rc = pim_msdp_mg_add(pim, mesh_group_name);
|
||||
if (rc != PIM_MSDP_ERR_NONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
mg = pim->msdp.mg;
|
||||
if (mg->src_ip.s_addr != INADDR_ANY) {
|
||||
pim_msdp_mg_src_do_del(pim);
|
||||
}
|
||||
mg->src_ip = src_ip;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
|
||||
pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip, mesh_group_name,
|
||||
&mbr->mp);
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_MSDP_EVENTS) {
|
||||
char ip_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", mg->src_ip, ip_str, sizeof(ip_str));
|
||||
zlog_debug("MSDP mesh-group %s src %s set", mg->mesh_group_name,
|
||||
ip_str);
|
||||
}
|
||||
return PIM_MSDP_ERR_NONE;
|
||||
}
|
||||
|
||||
/*********************** MSDP feature APIs *********************************/
|
||||
int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty,
|
||||
const char *spaces)
|
||||
{
|
||||
struct pim_msdp_mg *mg;
|
||||
struct listnode *mbrnode;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct pim_msdp_mg *mg = pim->msdp.mg;
|
||||
char mbr_str[INET_ADDRSTRLEN];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
int count = 0;
|
||||
|
||||
if (!mg) {
|
||||
if (SLIST_EMPTY(&pim->msdp.mglist))
|
||||
return count;
|
||||
|
||||
SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry) {
|
||||
if (mg->src_ip.s_addr != INADDR_ANY) {
|
||||
pim_inet4_dump("<src?>", mg->src_ip, src_str,
|
||||
sizeof(src_str));
|
||||
vty_out(vty, "%sip msdp mesh-group %s source %s\n",
|
||||
spaces, mg->mesh_group_name, src_str);
|
||||
++count;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
|
||||
pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str,
|
||||
sizeof(mbr_str));
|
||||
vty_out(vty, "%sip msdp mesh-group %s member %s\n",
|
||||
spaces, mg->mesh_group_name, mbr_str);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (mg->src_ip.s_addr != INADDR_ANY) {
|
||||
pim_inet4_dump("<src?>", mg->src_ip, src_str, sizeof(src_str));
|
||||
vty_out(vty, "%sip msdp mesh-group %s source %s\n", spaces,
|
||||
mg->mesh_group_name, src_str);
|
||||
++count;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
|
||||
pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
|
||||
vty_out(vty, "%sip msdp mesh-group %s member %s\n", spaces,
|
||||
mg->mesh_group_name, mbr_str);
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1623,11 +1449,13 @@ void pim_msdp_init(struct pim_instance *pim, struct thread_master *master)
|
||||
/* counterpart to MSDP init; XXX: unused currently */
|
||||
void pim_msdp_exit(struct pim_instance *pim)
|
||||
{
|
||||
struct pim_msdp_mg *mg;
|
||||
|
||||
pim_msdp_sa_adv_timer_setup(pim, false);
|
||||
|
||||
/* XXX: stop listener and delete all peer sessions */
|
||||
|
||||
pim_msdp_mg_free(pim);
|
||||
/* Stop listener and delete all peer sessions */
|
||||
while ((mg = SLIST_FIRST(&pim->msdp.mglist)) != NULL)
|
||||
pim_msdp_mg_free(pim, &mg);
|
||||
|
||||
if (pim->msdp.peer_hash) {
|
||||
hash_clean(pim->msdp.peer_hash, NULL);
|
||||
@ -1653,3 +1481,57 @@ void pim_msdp_exit(struct pim_instance *pim)
|
||||
stream_free(pim->msdp.work_obuf);
|
||||
pim->msdp.work_obuf = NULL;
|
||||
}
|
||||
|
||||
void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
|
||||
struct in_addr *ai)
|
||||
{
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct listnode *mbr_node;
|
||||
|
||||
/* Stop all connections and remove data structures. */
|
||||
pim_msdp_src_del(mg);
|
||||
|
||||
/* Set new address. */
|
||||
mg->src_ip = *ai;
|
||||
|
||||
/* No new address, disable everyone. */
|
||||
if (ai->s_addr == INADDR_ANY) {
|
||||
if (PIM_DEBUG_MSDP_EVENTS)
|
||||
zlog_debug("MSDP mesh-group %s src unset",
|
||||
mg->mesh_group_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create data structures and start TCP connection. */
|
||||
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr))
|
||||
pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
|
||||
mg->mesh_group_name, &mbr->mp);
|
||||
|
||||
if (PIM_DEBUG_MSDP_EVENTS)
|
||||
zlog_debug("MSDP mesh-group %s src %pI4 set",
|
||||
mg->mesh_group_name, &mg->src_ip);
|
||||
}
|
||||
|
||||
struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
|
||||
struct pim_msdp_mg *mg,
|
||||
struct in_addr *ia)
|
||||
{
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
|
||||
mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
|
||||
mbr->mbr_ip = *ia;
|
||||
listnode_add_sort(mg->mbr_list, mbr);
|
||||
|
||||
/* if valid SIP has been configured add peer session */
|
||||
if (mg->src_ip.s_addr != INADDR_ANY)
|
||||
pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
|
||||
mg->mesh_group_name, &mbr->mp);
|
||||
|
||||
if (PIM_DEBUG_MSDP_EVENTS)
|
||||
zlog_debug("MSDP mesh-group %s mbr %pI4 created",
|
||||
mg->mesh_group_name, &mbr->mbr_ip);
|
||||
|
||||
++mg->mbr_cnt;
|
||||
|
||||
return mbr;
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef PIM_MSDP_H
|
||||
#define PIM_MSDP_H
|
||||
|
||||
#include "lib/openbsd-queue.h"
|
||||
|
||||
enum pim_msdp_peer_state {
|
||||
PIM_MSDP_DISABLED,
|
||||
PIM_MSDP_INACTIVE,
|
||||
@ -160,8 +162,13 @@ struct pim_msdp_mg {
|
||||
struct in_addr src_ip;
|
||||
uint32_t mbr_cnt;
|
||||
struct list *mbr_list;
|
||||
|
||||
/** Belongs to PIM instance list. */
|
||||
SLIST_ENTRY(pim_msdp_mg) mg_entry;
|
||||
};
|
||||
|
||||
SLIST_HEAD(pim_mesh_group_list, pim_msdp_mg);
|
||||
|
||||
enum pim_msdp_flags {
|
||||
PIM_MSDPF_NONE = 0,
|
||||
PIM_MSDPF_ENABLE = (1 << 0),
|
||||
@ -196,8 +203,8 @@ struct pim_msdp {
|
||||
|
||||
struct in_addr originator_id;
|
||||
|
||||
/* currently only one mesh-group is supported - so just stash it here */
|
||||
struct pim_msdp_mg *mg;
|
||||
/** List of mesh groups. */
|
||||
struct pim_mesh_group_list mglist;
|
||||
};
|
||||
|
||||
#define PIM_MSDP_PEER_READ_ON(mp) \
|
||||
@ -246,17 +253,39 @@ bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp);
|
||||
void pim_msdp_up_join_state_changed(struct pim_instance *pim,
|
||||
struct pim_upstream *xg_up);
|
||||
void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg);
|
||||
enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
|
||||
const char *mesh_group_name,
|
||||
struct in_addr mbr_ip);
|
||||
enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
|
||||
const char *mesh_group_name,
|
||||
struct in_addr mbr_ip);
|
||||
enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
|
||||
const char *mesh_group_name);
|
||||
enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
|
||||
const char *mesh_group_name,
|
||||
struct in_addr src_ip);
|
||||
enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
|
||||
const char *mesh_group_name);
|
||||
|
||||
/**
|
||||
* Allocates a new mesh group data structure under PIM instance.
|
||||
*/
|
||||
struct pim_msdp_mg *pim_msdp_mg_new(struct pim_instance *pim,
|
||||
const char *mesh_group_name);
|
||||
/**
|
||||
* Deallocates mesh group data structure under PIM instance.
|
||||
*/
|
||||
void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg **mgp);
|
||||
|
||||
/**
|
||||
* Change the source address of a mesh group peers. It will do the following:
|
||||
* - Close all peers TCP connections
|
||||
* - Recreate peers data structure
|
||||
* - Start TCP connections with new local address.
|
||||
*/
|
||||
void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
|
||||
struct in_addr *ai);
|
||||
|
||||
/**
|
||||
* Add new peer to mesh group and starts the connection if source address is
|
||||
* configured.
|
||||
*/
|
||||
struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
|
||||
struct pim_msdp_mg *mg,
|
||||
struct in_addr *ia);
|
||||
|
||||
/**
|
||||
* Stops the connection and removes the peer data structures.
|
||||
*/
|
||||
void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr);
|
||||
|
||||
#endif
|
||||
|
@ -118,31 +118,24 @@ const struct frr_yang_module_info frr_pim_info = {
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group",
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups",
|
||||
.cbs = {
|
||||
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy,
|
||||
.create = pim_msdp_mesh_group_create,
|
||||
.destroy = pim_msdp_mesh_group_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name",
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy,
|
||||
.modify = pim_msdp_mesh_group_source_modify,
|
||||
.destroy = pim_msdp_mesh_group_source_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip",
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members",
|
||||
.cbs = {
|
||||
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy,
|
||||
.create = pim_msdp_mesh_group_members_create,
|
||||
.destroy = pim_msdp_mesh_group_members_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -60,22 +60,12 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
|
||||
struct nb_cb_create_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int pim_msdp_mesh_group_create(struct nb_cb_create_args *args);
|
||||
int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args);
|
||||
int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args);
|
||||
int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args);
|
||||
int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args);
|
||||
int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
|
||||
|
@ -243,147 +243,6 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
|
||||
const char *mg,
|
||||
char *errmsg, size_t errmsg_len)
|
||||
{
|
||||
enum pim_msdp_err result;
|
||||
|
||||
result = pim_msdp_mg_del(pim, mg);
|
||||
|
||||
switch (result) {
|
||||
case PIM_MSDP_ERR_NONE:
|
||||
break;
|
||||
case PIM_MSDP_ERR_NO_MG:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group does not exist");
|
||||
break;
|
||||
default:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"mesh-group source del failed");
|
||||
}
|
||||
|
||||
return result ? NB_ERR : NB_OK;
|
||||
}
|
||||
|
||||
static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
|
||||
const char *mg,
|
||||
struct in_addr mbr_ip,
|
||||
char *errmsg, size_t errmsg_len)
|
||||
{
|
||||
enum pim_msdp_err result;
|
||||
int ret = NB_OK;
|
||||
|
||||
result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
|
||||
|
||||
switch (result) {
|
||||
case PIM_MSDP_ERR_NONE:
|
||||
break;
|
||||
case PIM_MSDP_ERR_OOM:
|
||||
ret = NB_ERR;
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% Out of memory");
|
||||
break;
|
||||
case PIM_MSDP_ERR_MG_MBR_EXISTS:
|
||||
ret = NB_ERR;
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group member exists");
|
||||
break;
|
||||
case PIM_MSDP_ERR_MAX_MESH_GROUPS:
|
||||
ret = NB_ERR;
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% Only one mesh-group allowed currently");
|
||||
break;
|
||||
default:
|
||||
ret = NB_ERR;
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% member add failed");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
|
||||
const char *mg,
|
||||
struct in_addr mbr_ip,
|
||||
char *errmsg,
|
||||
size_t errmsg_len)
|
||||
{
|
||||
enum pim_msdp_err result;
|
||||
|
||||
result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
|
||||
|
||||
switch (result) {
|
||||
case PIM_MSDP_ERR_NONE:
|
||||
break;
|
||||
case PIM_MSDP_ERR_NO_MG:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group does not exist");
|
||||
break;
|
||||
case PIM_MSDP_ERR_NO_MG_MBR:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group member does not exist");
|
||||
break;
|
||||
default:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group member del failed");
|
||||
}
|
||||
|
||||
return result ? NB_ERR : NB_OK;
|
||||
}
|
||||
|
||||
static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
|
||||
const char *mg,
|
||||
struct in_addr src_ip,
|
||||
char *errmsg, size_t errmsg_len)
|
||||
{
|
||||
enum pim_msdp_err result;
|
||||
|
||||
result = pim_msdp_mg_src_add(pim, mg, src_ip);
|
||||
|
||||
switch (result) {
|
||||
case PIM_MSDP_ERR_NONE:
|
||||
break;
|
||||
case PIM_MSDP_ERR_OOM:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% Out of memory");
|
||||
break;
|
||||
case PIM_MSDP_ERR_MAX_MESH_GROUPS:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% Only one mesh-group allowed currently");
|
||||
break;
|
||||
default:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% source add failed");
|
||||
}
|
||||
|
||||
return result ? NB_ERR : NB_OK;
|
||||
}
|
||||
|
||||
static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
|
||||
const char *mg,
|
||||
char *errmsg,
|
||||
size_t errmsg_len)
|
||||
{
|
||||
enum pim_msdp_err result;
|
||||
|
||||
result = pim_msdp_mg_src_del(pim, mg);
|
||||
|
||||
switch (result) {
|
||||
case PIM_MSDP_ERR_NONE:
|
||||
break;
|
||||
case PIM_MSDP_ERR_NO_MG:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group does not exist");
|
||||
break;
|
||||
default:
|
||||
snprintf(errmsg, errmsg_len,
|
||||
"%% mesh-group source del failed");
|
||||
}
|
||||
|
||||
return result ? NB_ERR : NB_OK;
|
||||
}
|
||||
|
||||
static int ip_msdp_peer_cmd_worker(struct pim_instance *pim,
|
||||
struct in_addr peer_addr,
|
||||
struct in_addr local_addr,
|
||||
@ -1146,29 +1005,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group
|
||||
* XPath:
|
||||
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
|
||||
struct nb_cb_create_args *args)
|
||||
{
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
case NB_EV_APPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
int pim_msdp_mesh_group_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
const char *mesh_group_name;
|
||||
int result;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
@ -1177,16 +1020,29 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
mesh_group_name = yang_dnode_get_string(args->dnode, "mesh-group-name");
|
||||
mg = pim_msdp_mg_new(vrf->info, yang_dnode_get_string(
|
||||
args->dnode, "./name"));
|
||||
nb_running_set_entry(args->dnode, mg);
|
||||
break;
|
||||
}
|
||||
|
||||
result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name,
|
||||
args->errmsg,
|
||||
args->errmsg_len);
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
if (result != PIM_MSDP_ERR_NONE)
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
mg = nb_running_unset_entry(args->dnode);
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim_msdp_mg_free(vrf->info, &mg);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1194,67 +1050,71 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name
|
||||
* XPath:
|
||||
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args)
|
||||
{
|
||||
const char *mesh_group_name;
|
||||
const char *mesh_group_name_old;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
const struct lyd_node *vrf_dnode;
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf;
|
||||
struct ipaddr ip;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
mesh_group_name = yang_dnode_get_string(args->dnode, ".");
|
||||
yang_dnode_get_path(args->dnode, xpath, sizeof(xpath));
|
||||
|
||||
if (yang_dnode_exists(running_config->dnode, xpath) == false)
|
||||
break;
|
||||
|
||||
mesh_group_name_old = yang_dnode_get_string(
|
||||
running_config->dnode,
|
||||
xpath);
|
||||
if (strcmp(mesh_group_name, mesh_group_name_old)) {
|
||||
/* currently only one mesh-group can exist at a time */
|
||||
snprintf(args->errmsg, args->errmsg_len,
|
||||
"Only one mesh-group allowed currently");
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
break;
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
case NB_EV_APPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
mg = nb_running_get_entry(args->dnode, NULL, true);
|
||||
vrf_dnode =
|
||||
yang_dnode_get_parent(args->dnode, "address-family");
|
||||
vrf = nb_running_get_entry(vrf_dnode, "../../", true);
|
||||
yang_dnode_get_ip(&ip, args->dnode, NULL);
|
||||
|
||||
pim_msdp_mg_src_add(vrf->info, mg, &ip.ip._v4_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
const struct lyd_node *vrf_dnode;
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf;
|
||||
struct in_addr addr;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
mg = nb_running_get_entry(args->dnode, NULL, true);
|
||||
vrf_dnode =
|
||||
yang_dnode_get_parent(args->dnode, "address-family");
|
||||
vrf = nb_running_get_entry(vrf_dnode, "../../", true);
|
||||
|
||||
addr.s_addr = INADDR_ANY;
|
||||
pim_msdp_mg_src_add(vrf->info, mg, &addr);
|
||||
break;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip
|
||||
* XPath:
|
||||
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
|
||||
struct nb_cb_create_args *args)
|
||||
int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args)
|
||||
{
|
||||
const struct lyd_node *vrf_dnode;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct pim_msdp_mg *mg;
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
const char *mesh_group_name;
|
||||
struct ipaddr mbr_ip;
|
||||
enum pim_msdp_err result;
|
||||
struct ipaddr ip;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
@ -1262,33 +1122,24 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
mesh_group_name = yang_dnode_get_string(args->dnode,
|
||||
"../mesh-group-name");
|
||||
yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
|
||||
|
||||
result = ip_msdp_mesh_group_member_cmd_worker(
|
||||
pim, mesh_group_name, mbr_ip.ip._v4_addr,
|
||||
args->errmsg, args->errmsg_len);
|
||||
|
||||
if (result != PIM_MSDP_ERR_NONE)
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
mg = nb_running_get_entry(args->dnode, NULL, true);
|
||||
vrf_dnode =
|
||||
yang_dnode_get_parent(args->dnode, "address-family");
|
||||
vrf = nb_running_get_entry(vrf_dnode, "../../", true);
|
||||
yang_dnode_get_ip(&ip, args->dnode, "address");
|
||||
|
||||
mbr = pim_msdp_mg_mbr_add(vrf->info, mg, &ip.ip._v4_addr);
|
||||
nb_running_set_entry(args->dnode, mbr);
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
const char *mesh_group_name;
|
||||
struct ipaddr mbr_ip;
|
||||
enum pim_msdp_err result;
|
||||
struct pim_msdp_mg_mbr *mbr;
|
||||
struct pim_msdp_mg *mg;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
@ -1296,92 +1147,16 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
mesh_group_name = yang_dnode_get_string(args->dnode,
|
||||
"../mesh-group-name");
|
||||
yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
|
||||
|
||||
result = ip_no_msdp_mesh_group_member_cmd_worker(
|
||||
pim, mesh_group_name, mbr_ip.ip._v4_addr,
|
||||
args->errmsg, args->errmsg_len);
|
||||
|
||||
if (result != PIM_MSDP_ERR_NONE)
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
mbr = nb_running_get_entry(args->dnode, NULL, true);
|
||||
mg = nb_running_get_entry(args->dnode, "../", true);
|
||||
|
||||
pim_msdp_mg_mbr_del(mg, mbr);
|
||||
break;
|
||||
}
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
const char *mesh_group_name;
|
||||
struct ipaddr src_ip;
|
||||
enum pim_msdp_err result;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
mesh_group_name = yang_dnode_get_string(args->dnode,
|
||||
"../mesh-group-name");
|
||||
yang_dnode_get_ip(&src_ip, args->dnode, NULL);
|
||||
|
||||
result = ip_msdp_mesh_group_source_cmd_worker(
|
||||
pim, mesh_group_name, src_ip.ip._v4_addr,
|
||||
args->errmsg, args->errmsg_len);
|
||||
|
||||
if (result != PIM_MSDP_ERR_NONE)
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
|
||||
break;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
const char *mesh_group_name;
|
||||
enum pim_msdp_err result;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
mesh_group_name = yang_dnode_get_string(args->dnode,
|
||||
"../mesh-group-name");
|
||||
|
||||
result = ip_no_msdp_mesh_group_source_cmd_worker(
|
||||
pim, mesh_group_name, args->errmsg,
|
||||
args->errmsg_len);
|
||||
|
||||
if (result != PIM_MSDP_ERR_NONE)
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
|
||||
break;
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer
|
||||
*/
|
||||
|
129
tests/topotests/lib/mcast-tester.py
Executable file
129
tests/topotests/lib/mcast-tester.py
Executable file
@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2021 by
|
||||
# Network Device Education Foundation, Inc. ("NetDEF")
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""
|
||||
Subscribe to a multicast group so that the kernel sends an IGMP JOIN
|
||||
for the multicast group we subscribed to.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import json
|
||||
import socket
|
||||
import subprocess
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
|
||||
#
|
||||
# Functions
|
||||
#
|
||||
def interface_name_to_index(name):
|
||||
"Gets the interface index using its name. Returns None on failure."
|
||||
interfaces = json.loads(
|
||||
subprocess.check_output('ip -j link show', shell=True))
|
||||
|
||||
for interface in interfaces:
|
||||
if interface['ifname'] == name:
|
||||
return interface['ifindex']
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def multicast_join(sock, ifindex, group, port):
|
||||
"Joins a multicast group."
|
||||
mreq = struct.pack(
|
||||
"=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex
|
||||
)
|
||||
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind((group, port))
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||
|
||||
|
||||
#
|
||||
# Main code.
|
||||
#
|
||||
parser = argparse.ArgumentParser(description="Multicast RX utility")
|
||||
parser.add_argument('socket', help='Point to topotest UNIX socket')
|
||||
parser.add_argument('group', help='Multicast IP')
|
||||
parser.add_argument('interface', help='Interface name')
|
||||
parser.add_argument(
|
||||
'--send',
|
||||
help='Transmit instead of join with interval (defaults to 0.7 sec)',
|
||||
type=float, default=0)
|
||||
args = parser.parse_args()
|
||||
|
||||
ttl = 16
|
||||
port = 1000
|
||||
|
||||
# Get interface index/validate.
|
||||
ifindex = interface_name_to_index(args.interface)
|
||||
if ifindex is None:
|
||||
sys.stderr.write('Interface {} does not exists\n'.format(args.interface))
|
||||
sys.exit(1)
|
||||
|
||||
# We need root privileges to set up multicast.
|
||||
if os.geteuid() != 0:
|
||||
sys.stderr.write("ERROR: You must have root privileges\n")
|
||||
sys.exit(1)
|
||||
|
||||
# Wait for topotest to synchronize with us.
|
||||
toposock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
|
||||
while True:
|
||||
try:
|
||||
toposock.connect(args.socket)
|
||||
break
|
||||
except ConnectionRefusedError:
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
msock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
if args.send > 0:
|
||||
# Prepare multicast bit in that interface.
|
||||
msock.setsockopt(
|
||||
socket.SOL_SOCKET, 25,
|
||||
struct.pack("%ds" % len(args.interface),
|
||||
args.interface.encode('utf-8')))
|
||||
# Set packets TTL.
|
||||
msock.setsockopt(
|
||||
socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack("b", ttl))
|
||||
# Block to ensure packet send.
|
||||
msock.setblocking(True)
|
||||
# Set topotest socket non blocking so we can multiplex the main loop.
|
||||
toposock.setblocking(False)
|
||||
else:
|
||||
multicast_join(msock, ifindex, args.group, port)
|
||||
|
||||
counter = 0
|
||||
while True:
|
||||
if args.send > 0:
|
||||
msock.sendto(b"test %d" % counter, (args.group, port))
|
||||
counter += 1
|
||||
time.sleep(args.send)
|
||||
|
||||
try:
|
||||
data = toposock.recv(1)
|
||||
if data == b'':
|
||||
print(' -> Connection closed')
|
||||
break
|
||||
except BlockingIOError:
|
||||
continue
|
||||
|
||||
msock.close()
|
||||
|
||||
sys.exit(0)
|
@ -222,6 +222,22 @@ class Topogen(object):
|
||||
self.peern += 1
|
||||
return self.gears[name]
|
||||
|
||||
def add_host(self, name, ip, defaultRoute):
|
||||
"""
|
||||
Adds a new host to the topology. This function has the following
|
||||
parameters:
|
||||
* `ip`: the peer address (e.g. '1.2.3.4/24')
|
||||
* `defaultRoute`: the peer default route (e.g. 'via 1.2.3.1')
|
||||
"""
|
||||
if name is None:
|
||||
name = "host{}".format(self.peern)
|
||||
if name in self.gears:
|
||||
raise KeyError("host already exists")
|
||||
|
||||
self.gears[name] = TopoHost(self, name, ip=ip, defaultRoute=defaultRoute)
|
||||
self.peern += 1
|
||||
return self.gears[name]
|
||||
|
||||
def add_link(self, node1, node2, ifname1=None, ifname2=None):
|
||||
"""
|
||||
Creates a connection between node1 and node2. The nodes can be the
|
||||
|
0
tests/topotests/msdp_mesh_topo1/__init__.py
Normal file
0
tests/topotests/msdp_mesh_topo1/__init__.py
Normal file
7
tests/topotests/msdp_mesh_topo1/r1/bgpd.conf
Normal file
7
tests/topotests/msdp_mesh_topo1/r1/bgpd.conf
Normal file
@ -0,0 +1,7 @@
|
||||
router bgp 65000
|
||||
neighbor 10.254.254.2 remote-as 65000
|
||||
neighbor 10.254.254.2 update-source 10.254.254.1
|
||||
address-family ipv4 unicast
|
||||
redistribute connected
|
||||
exit-address-family
|
||||
!
|
8
tests/topotests/msdp_mesh_topo1/r1/ospfd.conf
Normal file
8
tests/topotests/msdp_mesh_topo1/r1/ospfd.conf
Normal file
@ -0,0 +1,8 @@
|
||||
interface r1-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
!
|
||||
router ospf
|
||||
network 192.168.1.0/24 area 0.0.0.0
|
||||
redistribute connected
|
||||
!
|
15
tests/topotests/msdp_mesh_topo1/r1/pimd.conf
Normal file
15
tests/topotests/msdp_mesh_topo1/r1/pimd.conf
Normal file
@ -0,0 +1,15 @@
|
||||
interface lo
|
||||
ip pim
|
||||
ip pim use-source 10.254.254.1
|
||||
!
|
||||
interface r1-eth0
|
||||
ip pim
|
||||
!
|
||||
interface r1-eth1
|
||||
ip pim
|
||||
ip igmp
|
||||
!
|
||||
ip pim rp 10.254.254.1
|
||||
ip msdp mesh-group mg-1 source 10.254.254.1
|
||||
ip msdp mesh-group mg-1 member 10.254.254.2
|
||||
ip msdp mesh-group mg-1 member 10.254.254.3
|
11
tests/topotests/msdp_mesh_topo1/r1/zebra.conf
Normal file
11
tests/topotests/msdp_mesh_topo1/r1/zebra.conf
Normal file
@ -0,0 +1,11 @@
|
||||
ip forwarding
|
||||
!
|
||||
interface lo
|
||||
ip address 10.254.254.1/32
|
||||
!
|
||||
interface r1-eth0
|
||||
ip address 192.168.1.2/24
|
||||
!
|
||||
interface r1-eth1
|
||||
ip address 192.168.10.1/24
|
||||
!
|
10
tests/topotests/msdp_mesh_topo1/r2/bgpd.conf
Normal file
10
tests/topotests/msdp_mesh_topo1/r2/bgpd.conf
Normal file
@ -0,0 +1,10 @@
|
||||
router bgp 65000
|
||||
neighbor pg-1 peer-group
|
||||
neighbor pg-1 update-source 10.254.254.1
|
||||
neighbor pg-1 remote-as 65000
|
||||
neighbor 10.254.254.1 peer-group pg-1
|
||||
neighbor 10.254.254.3 peer-group pg-1
|
||||
address-family ipv4 unicast
|
||||
redistribute connected
|
||||
exit-address-family
|
||||
!
|
13
tests/topotests/msdp_mesh_topo1/r2/ospfd.conf
Normal file
13
tests/topotests/msdp_mesh_topo1/r2/ospfd.conf
Normal file
@ -0,0 +1,13 @@
|
||||
interface r2-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
!
|
||||
interface r2-eth1
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
!
|
||||
router ospf
|
||||
network 192.168.1.0/24 area 0.0.0.0
|
||||
network 192.168.2.0/24 area 0.0.0.0
|
||||
redistribute connected
|
||||
!
|
14
tests/topotests/msdp_mesh_topo1/r2/pimd.conf
Normal file
14
tests/topotests/msdp_mesh_topo1/r2/pimd.conf
Normal file
@ -0,0 +1,14 @@
|
||||
interface lo
|
||||
ip pim
|
||||
ip pim use-source 10.254.254.2
|
||||
!
|
||||
interface r2-eth0
|
||||
ip pim
|
||||
!
|
||||
interface r2-eth1
|
||||
ip pim
|
||||
!
|
||||
ip pim rp 10.254.254.2
|
||||
ip msdp mesh-group mg-1 source 10.254.254.2
|
||||
ip msdp mesh-group mg-1 member 10.254.254.1
|
||||
ip msdp mesh-group mg-1 member 10.254.254.3
|
11
tests/topotests/msdp_mesh_topo1/r2/zebra.conf
Normal file
11
tests/topotests/msdp_mesh_topo1/r2/zebra.conf
Normal file
@ -0,0 +1,11 @@
|
||||
ip forwarding
|
||||
!
|
||||
interface lo
|
||||
ip address 10.254.254.2/32
|
||||
!
|
||||
interface r2-eth0
|
||||
ip address 192.168.1.1/24
|
||||
!
|
||||
interface r2-eth1
|
||||
ip address 192.168.2.1/24
|
||||
!
|
7
tests/topotests/msdp_mesh_topo1/r3/bgpd.conf
Normal file
7
tests/topotests/msdp_mesh_topo1/r3/bgpd.conf
Normal file
@ -0,0 +1,7 @@
|
||||
router bgp 65000
|
||||
neighbor 192.168.2.1 remote-as 65000
|
||||
neighbor 192.168.2.1 update-source 10.254.254.3
|
||||
address-family ipv4 unicast
|
||||
redistribute connected
|
||||
exit-address-family
|
||||
!
|
8
tests/topotests/msdp_mesh_topo1/r3/ospfd.conf
Normal file
8
tests/topotests/msdp_mesh_topo1/r3/ospfd.conf
Normal file
@ -0,0 +1,8 @@
|
||||
interface r3-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
!
|
||||
router ospf
|
||||
network 192.168.2.0/24 area 0.0.0.0
|
||||
redistribute connected
|
||||
!
|
15
tests/topotests/msdp_mesh_topo1/r3/pimd.conf
Normal file
15
tests/topotests/msdp_mesh_topo1/r3/pimd.conf
Normal file
@ -0,0 +1,15 @@
|
||||
interface lo
|
||||
ip pim
|
||||
ip pim use-source 10.254.254.3
|
||||
!
|
||||
interface r3-eth0
|
||||
ip pim
|
||||
!
|
||||
interface r3-eth1
|
||||
ip pim
|
||||
ip igmp
|
||||
!
|
||||
ip pim rp 10.254.254.3
|
||||
ip msdp mesh-group mg-1 source 10.254.254.3
|
||||
ip msdp mesh-group mg-1 member 10.254.254.1
|
||||
ip msdp mesh-group mg-1 member 10.254.254.2
|
11
tests/topotests/msdp_mesh_topo1/r3/zebra.conf
Normal file
11
tests/topotests/msdp_mesh_topo1/r3/zebra.conf
Normal file
@ -0,0 +1,11 @@
|
||||
ip forwarding
|
||||
!
|
||||
interface lo
|
||||
ip address 10.254.254.3/32
|
||||
!
|
||||
interface r3-eth0
|
||||
ip address 192.168.2.2/24
|
||||
!
|
||||
interface r3-eth1
|
||||
ip address 192.168.30.1/24
|
||||
!
|
88
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot
Normal file
88
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot
Normal file
@ -0,0 +1,88 @@
|
||||
## Color coding:
|
||||
#########################
|
||||
## Main FRR: #f08080 red
|
||||
## Switches: #d0e0d0 gray
|
||||
## RIP: #19e3d9 Cyan
|
||||
## RIPng: #fcb314 dark yellow
|
||||
## OSPFv2: #32b835 Green
|
||||
## OSPFv3: #19e3d9 Cyan
|
||||
## ISIS IPv4 #fcb314 dark yellow
|
||||
## ISIS IPv6 #9a81ec purple
|
||||
## BGP IPv4 #eee3d3 beige
|
||||
## BGP IPv6 #fdff00 yellow
|
||||
##### Colors (see http://www.color-hex.com/)
|
||||
|
||||
graph template {
|
||||
label="msdp_mesh_topo1";
|
||||
|
||||
# Routers
|
||||
r1 [
|
||||
shape=doubleoctagon,
|
||||
label="r1",
|
||||
fillcolor="#f08080",
|
||||
style=filled,
|
||||
];
|
||||
r2 [
|
||||
shape=doubleoctagon
|
||||
label="r2",
|
||||
fillcolor="#f08080",
|
||||
style=filled,
|
||||
];
|
||||
r3 [
|
||||
shape=doubleoctagon
|
||||
label="r3",
|
||||
fillcolor="#f08080",
|
||||
style=filled,
|
||||
];
|
||||
h1 [
|
||||
shape=doubleoctagon
|
||||
label="h1",
|
||||
fillcolor="#4f4f4f",
|
||||
style=filled,
|
||||
];
|
||||
h2 [
|
||||
shape=doubleoctagon
|
||||
label="h2",
|
||||
fillcolor="#4f4f4f",
|
||||
style=filled,
|
||||
];
|
||||
|
||||
# Switches
|
||||
s1 [
|
||||
shape=oval,
|
||||
label="sw1\n192.168.1.0/24",
|
||||
fillcolor="#d0e0d0",
|
||||
style=filled,
|
||||
];
|
||||
s2 [
|
||||
shape=oval,
|
||||
label="sw2\n192.168.2.0/24",
|
||||
fillcolor="#d0e0d0",
|
||||
style=filled,
|
||||
];
|
||||
s3 [
|
||||
shape=oval,
|
||||
label="sw3\n192.168.10.0/24",
|
||||
fillcolor="#d0e0d0",
|
||||
style=filled,
|
||||
];
|
||||
s4 [
|
||||
shape=oval,
|
||||
label="sw3\n192.168.30.0/24",
|
||||
fillcolor="#d0e0d0",
|
||||
style=filled,
|
||||
];
|
||||
|
||||
# Connections
|
||||
r1 -- s1 [label="eth0\n.2"];
|
||||
r2 -- s1 [label="eth0\n.1"];
|
||||
|
||||
r2 -- s2 [label="eth1\n.1"];
|
||||
r3 -- s2 [label="eth0\n.2"];
|
||||
|
||||
r1 -- s3 [label="eth1\n.1"];
|
||||
h1 -- s3 [label="eth0\n.2"];
|
||||
|
||||
r3 -- s4 [label="eth1\n.1"];
|
||||
h2 -- s4 [label="eth0\n.2"];
|
||||
}
|
BIN
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png
Normal file
BIN
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
296
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
Normal file
296
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
Normal file
@ -0,0 +1,296 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# test_msdp_mesh_topo1.py
|
||||
# Part of NetDEF Topology Tests
|
||||
#
|
||||
# Copyright (C) 2021 by
|
||||
# Network Device Education Foundation, Inc. ("NetDEF")
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
"""
|
||||
test_msdp_mesh_topo1.py: Test the FRR PIM MSDP mesh groups.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from functools import partial
|
||||
import pytest
|
||||
import socket
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
from mininet.topo import Topo
|
||||
|
||||
pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.pimd]
|
||||
|
||||
#
|
||||
# Test global variables:
|
||||
# They are used to handle communicating with external application.
|
||||
#
|
||||
APP_SOCK_PATH = '/tmp/topotests/apps.sock'
|
||||
HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py")
|
||||
app_listener = None
|
||||
app_clients = {}
|
||||
|
||||
def listen_to_applications():
|
||||
"Start listening socket to connect with applications."
|
||||
# Remove old socket.
|
||||
try:
|
||||
os.unlink(APP_SOCK_PATH)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
|
||||
sock.bind(APP_SOCK_PATH)
|
||||
sock.listen(10)
|
||||
global app_listener
|
||||
app_listener = sock
|
||||
|
||||
def accept_host(host):
|
||||
"Accept connection from application running in hosts."
|
||||
global app_listener, app_clients
|
||||
conn = app_listener.accept()
|
||||
app_clients[host] = {
|
||||
'fd': conn[0],
|
||||
'address': conn[1]
|
||||
}
|
||||
|
||||
def close_applications():
|
||||
"Signal applications to stop and close all sockets."
|
||||
global app_listener, app_clients
|
||||
|
||||
# Close listening socket.
|
||||
app_listener.close()
|
||||
|
||||
# Remove old socket.
|
||||
try:
|
||||
os.unlink(APP_SOCK_PATH)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Close all host connections.
|
||||
for host in ["h1", "h2"]:
|
||||
if app_clients.get(host) is None:
|
||||
continue
|
||||
app_clients["h1"]["fd"].close()
|
||||
|
||||
|
||||
class MSDPMeshTopo1(Topo):
|
||||
"Test topology builder"
|
||||
|
||||
def build(self, *_args, **_opts):
|
||||
"Build function"
|
||||
tgen = get_topogen(self)
|
||||
|
||||
# Create 3 routers
|
||||
for routern in range(1, 4):
|
||||
tgen.add_router("r{}".format(routern))
|
||||
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["r1"])
|
||||
switch.add_link(tgen.gears["r2"])
|
||||
|
||||
switch = tgen.add_switch("s2")
|
||||
switch.add_link(tgen.gears["r2"])
|
||||
switch.add_link(tgen.gears["r3"])
|
||||
|
||||
# Create stub networks for multicast traffic.
|
||||
tgen.add_host("h1", "192.168.10.2/24", "192.168.10.1")
|
||||
switch = tgen.add_switch("s3")
|
||||
switch.add_link(tgen.gears["r1"])
|
||||
switch.add_link(tgen.gears["h1"])
|
||||
|
||||
tgen.add_host("h2", "192.168.30.2/24", "192.168.30.1")
|
||||
switch = tgen.add_switch("s4")
|
||||
switch.add_link(tgen.gears["r3"])
|
||||
switch.add_link(tgen.gears["h2"])
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"Sets up the pytest environment"
|
||||
tgen = Topogen(MSDPMeshTopo1, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
for rname, router in router_list.items():
|
||||
daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
|
||||
if os.path.isfile(daemon_file):
|
||||
router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
|
||||
|
||||
daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
|
||||
if os.path.isfile(daemon_file):
|
||||
router.load_config(TopoRouter.RD_BGP, daemon_file)
|
||||
|
||||
daemon_file = "{}/{}/ospfd.conf".format(CWD, rname)
|
||||
if os.path.isfile(daemon_file):
|
||||
router.load_config(TopoRouter.RD_OSPF, daemon_file)
|
||||
|
||||
daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
|
||||
if os.path.isfile(daemon_file):
|
||||
router.load_config(TopoRouter.RD_PIM, daemon_file)
|
||||
|
||||
# Initialize all routers.
|
||||
tgen.start_router()
|
||||
|
||||
# Start applications socket.
|
||||
listen_to_applications()
|
||||
|
||||
|
||||
def test_wait_ospf_convergence():
|
||||
"Wait for OSPF to converge"
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("waiting for protocols to converge")
|
||||
|
||||
def expect_loopback_route(router, iptype, route, proto):
|
||||
"Wait until route is present on RIB for protocol."
|
||||
logger.info("waiting route {} in {}".format(route, router))
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears[router],
|
||||
"show {} route json".format(iptype),
|
||||
{route: [{"protocol": proto}]}
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=40, wait=1)
|
||||
assertmsg = '"{}" OSPF convergence failure'.format(router)
|
||||
assert result is None, assertmsg
|
||||
|
||||
# Wait for R1 <-> R2 convergence.
|
||||
expect_loopback_route("r1", "ip", "10.254.254.2/32", "ospf")
|
||||
# Wait for R1 <-> R3 convergence.
|
||||
expect_loopback_route("r1", "ip", "10.254.254.3/32", "ospf")
|
||||
|
||||
# Wait for R2 <-> R1 convergence.
|
||||
expect_loopback_route("r2", "ip", "10.254.254.1/32", "ospf")
|
||||
# Wait for R2 <-> R3 convergence.
|
||||
expect_loopback_route("r2", "ip", "10.254.254.3/32", "ospf")
|
||||
|
||||
# Wait for R3 <-> R1 convergence.
|
||||
expect_loopback_route("r3", "ip", "10.254.254.1/32", "ospf")
|
||||
# Wait for R3 <-> R2 convergence.
|
||||
expect_loopback_route("r3", "ip", "10.254.254.2/32", "ospf")
|
||||
|
||||
|
||||
def test_wait_msdp_convergence():
|
||||
"Wait for MSDP to converge"
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("test MSDP convergence")
|
||||
|
||||
tgen.gears["h1"].run("{} --send='0.7' '{}' '{}' '{}' &".format(
|
||||
HELPER_APP_PATH, APP_SOCK_PATH, '229.0.1.10', 'h1-eth0'))
|
||||
accept_host("h1")
|
||||
|
||||
tgen.gears["h2"].run("{} '{}' '{}' '{}' &".format(
|
||||
HELPER_APP_PATH, APP_SOCK_PATH, '229.0.1.10', 'h2-eth0'))
|
||||
accept_host("h2")
|
||||
|
||||
def expect_msdp_peer(router, peer, sa_count=0):
|
||||
"Expect MSDP peer connection to be established with SA amount."
|
||||
logger.info("waiting MSDP connection from peer {} on router {}".format(peer, router))
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears[router],
|
||||
"show ip msdp peer json",
|
||||
{peer: {"state": "established", "saCount": sa_count}}
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assertmsg = '"{}" MSDP connection failure'.format(router)
|
||||
assert result is None, assertmsg
|
||||
|
||||
# R1 peers.
|
||||
expect_msdp_peer("r1", "10.254.254.2")
|
||||
expect_msdp_peer("r1", "10.254.254.3")
|
||||
|
||||
# R2 peers.
|
||||
expect_msdp_peer("r2", "10.254.254.1", 1)
|
||||
expect_msdp_peer("r2", "10.254.254.3")
|
||||
|
||||
# R3 peers.
|
||||
expect_msdp_peer("r3", "10.254.254.1", 1)
|
||||
expect_msdp_peer("r3", "10.254.254.2")
|
||||
|
||||
|
||||
def test_msdp_sa_configuration():
|
||||
"Expect the multicast traffic SA to be created"
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("test MSDP SA")
|
||||
|
||||
def expect_msdp_sa(router, source, group, local, rp, spt_setup):
|
||||
"Expect MSDP SA."
|
||||
logger.info("waiting MSDP SA on router {}".format(router))
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears[router],
|
||||
"show ip msdp sa json",
|
||||
{group: {source: {"local": local, "rp": rp, "sptSetup": spt_setup}}}
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assertmsg = '"{}" MSDP SA failure'.format(router)
|
||||
assert result is None, assertmsg
|
||||
|
||||
source = "192.168.10.2"
|
||||
group = "229.0.1.10"
|
||||
rp = "10.254.254.1"
|
||||
|
||||
# R1 SA.
|
||||
expect_msdp_sa("r1", source, group, "yes", "-", "-")
|
||||
|
||||
# R2 SA.
|
||||
expect_msdp_sa("r2", source, group, "no", rp, "no")
|
||||
|
||||
# R3 peers.
|
||||
expect_msdp_sa("r3", source, group, "no", rp, "yes")
|
||||
|
||||
|
||||
def teardown_module(_mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
close_applications()
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_memory_leak():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
if not tgen.is_memleak_enabled():
|
||||
pytest.skip("Memory leak test/report is disabled")
|
||||
|
||||
tgen.report_memory_leaks()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -174,26 +174,36 @@ module frr-pim {
|
||||
"Enable ssmpingd operation.";
|
||||
}
|
||||
|
||||
container msdp-mesh-group {
|
||||
presence
|
||||
"Configure MSDP mesh-group.";
|
||||
list msdp-mesh-groups {
|
||||
key "name";
|
||||
description
|
||||
"RFC 3618 Section 10.2. MSDP mesh-group semantics
|
||||
|
||||
leaf mesh-group-name {
|
||||
type string;
|
||||
Groups multiple MSDP peers to reduce SA flooding typically used
|
||||
in intra-domain settings.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length 1..64;
|
||||
}
|
||||
description
|
||||
"MSDP mesh group name.";
|
||||
"The mesh group name.";
|
||||
}
|
||||
|
||||
leaf-list member-ip {
|
||||
leaf source {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"Peer ip address.";
|
||||
"Source IP address for the TCP connections.";
|
||||
}
|
||||
|
||||
leaf source-ip {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"Source ip address for the TCP connection.";
|
||||
list members {
|
||||
key "address";
|
||||
|
||||
leaf address {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"Peer member IP address.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user