Merge pull request #8561 from opensourcerouting/msdp-refactor-v2

pimd: rework MSDP mesh groups
This commit is contained in:
Donald Sharp 2021-06-10 09:44:28 -04:00 committed by GitHub
commit 59ec133a03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1152 additions and 845 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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,
}
},
{

View File

@ -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(

View File

@ -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
*/

View 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)

View File

@ -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

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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
!

View 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

View 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
!

View 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
!

View 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
!

View 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

View 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
!

View 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"];
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View 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))

View File

@ -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.";
}
}
}