diff options
author | anuradhak <anuradhak@cumulusnetworks.com> | 2016-11-12 14:39:44 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-12-22 02:26:15 +0100 |
commit | 977d71cc7abc10e9ee4d496de3a4b9fb118df002 (patch) | |
tree | 9979259e6d33b379e3f50af962f0b837c939e810 | |
parent | pimd: Backing up broken state. (diff) | |
download | frr-977d71cc7abc10e9ee4d496de3a4b9fb118df002.tar.xz frr-977d71cc7abc10e9ee4d496de3a4b9fb118df002.zip |
pim-msdp: part-4: cli cleanup
1. Add support for mesh-group based configuration that is easy to apply
via automation. The older per-peer configuartion is temporarily hidden
and will be cleaned up later.
Sample config -
ip msdp mesh-group cumulus source 100.1.1.4
ip msdp mesh-group cumulus member 100.1.1.5
ip msdp mesh-group cumulus member 100.1.1.6
2. Added support for detail peer and sa-cache displays. Along with
filter keys.
3. Add json output for all the msdp displays.
With this commit basic support for anycast-RP with MSDP (in numbered
network is complete). Unnumbered support will be added separately.
Ticket: CM-13306
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
-rw-r--r-- | pimd/pim_cmd.c | 662 | ||||
-rw-r--r-- | pimd/pim_cmd.h | 1 | ||||
-rw-r--r-- | pimd/pim_memory.c | 4 | ||||
-rw-r--r-- | pimd/pim_memory.h | 4 | ||||
-rw-r--r-- | pimd/pim_msdp.c | 383 | ||||
-rw-r--r-- | pimd/pim_msdp.h | 34 | ||||
-rw-r--r-- | pimd/pim_vty.c | 4 |
7 files changed, 1024 insertions, 68 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 03856bdfc..84350676a 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -5170,7 +5170,7 @@ ip_msdp_peer_cmd_worker (struct vty *vty, const char *peer, const char *local) return CMD_WARNING; } - result = pim_msdp_peer_add(peer_addr, local_addr, "default"); + result = pim_msdp_peer_add(peer_addr, local_addr, "default", NULL/* mp_p */); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -5190,7 +5190,7 @@ ip_msdp_peer_cmd_worker (struct vty *vty, const char *peer, const char *local) return result?CMD_WARNING:CMD_SUCCESS; } -DEFUN (ip_msdp_peer, +DEFUN_HIDDEN (ip_msdp_peer, ip_msdp_peer_cmd, "ip msdp peer A.B.C.D source A.B.C.D", IP_STR @@ -5230,9 +5230,10 @@ ip_no_msdp_peer_cmd_worker (struct vty *vty, const char *peer) return result?CMD_WARNING:CMD_SUCCESS; } -DEFUN (no_ip_msdp_peer, +DEFUN_HIDDEN (no_ip_msdp_peer, no_ip_msdp_peer_cmd, "no ip msdp peer A.B.C.D", + NO_STR IP_STR CFG_MSDP_STR "Delete MSDP peer\n" @@ -5241,6 +5242,275 @@ DEFUN (no_ip_msdp_peer, return ip_no_msdp_peer_cmd_worker (vty, argv[4]->arg); } +static int +ip_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg, const char *mbr) +{ + enum pim_msdp_err result; + struct in_addr mbr_ip; + + result = inet_pton(AF_INET, mbr, &mbr_ip); + if (result <= 0) { + vty_out(vty, "%% Bad member address %s: errno=%d: %s%s", + mbr, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_msdp_mg_mbr_add(mg, mbr_ip); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_OOM: + vty_out(vty, "%% Out of memory%s", VTY_NEWLINE); + break; + case PIM_MSDP_ERR_MG_MBR_EXISTS: + vty_out(vty, "%% mesh-group member exists%s", VTY_NEWLINE); + break; + case PIM_MSDP_ERR_MAX_MESH_GROUPS: + vty_out(vty, "%% Only one mesh-group allowed currently%s", VTY_NEWLINE); + break; + default: + vty_out(vty, "%% member add failed%s", VTY_NEWLINE); + } + + return result?CMD_WARNING:CMD_SUCCESS; +} + +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") +{ + return ip_msdp_mesh_group_member_cmd_worker(vty, argv[3]->arg, argv[5]->arg); +} + +static int +ip_no_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg, const char *mbr) +{ + enum pim_msdp_err result; + struct in_addr mbr_ip; + + result = inet_pton(AF_INET, mbr, &mbr_ip); + if (result <= 0) { + vty_out(vty, "%% Bad member address %s: errno=%d: %s%s", + mbr, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_msdp_mg_mbr_del(mg, mbr_ip); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_MG: + vty_out(vty, "%% mesh-group does not exist%s", VTY_NEWLINE); + break; + case PIM_MSDP_ERR_NO_MG_MBR: + vty_out(vty, "%% mesh-group member does not exist%s", VTY_NEWLINE); + break; + default: + vty_out(vty, "%% mesh-group member del failed%s", VTY_NEWLINE); + } + + return result?CMD_WARNING:CMD_SUCCESS; +} +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") +{ + return ip_no_msdp_mesh_group_member_cmd_worker(vty, argv[4]->arg, argv[6]->arg); +} + +static int +ip_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg, const char *src) +{ + enum pim_msdp_err result; + struct in_addr src_ip; + + result = inet_pton(AF_INET, src, &src_ip); + if (result <= 0) { + vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", + src, errno, safe_strerror(errno), VTY_NEWLINE); + return CMD_WARNING; + } + + result = pim_msdp_mg_src_add(mg, src_ip); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_OOM: + vty_out(vty, "%% Out of memory%s", VTY_NEWLINE); + break; + case PIM_MSDP_ERR_MAX_MESH_GROUPS: + vty_out(vty, "%% Only one mesh-group allowed currently%s", VTY_NEWLINE); + break; + default: + vty_out(vty, "%% source add failed%s", VTY_NEWLINE); + } + + return result?CMD_WARNING: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") +{ + return ip_msdp_mesh_group_source_cmd_worker(vty, argv[3]->arg, argv[5]->arg); +} + +static int +ip_no_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg) +{ + enum pim_msdp_err result; + + result = pim_msdp_mg_src_del(mg); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_MG: + vty_out(vty, "%% mesh-group does not exist%s", VTY_NEWLINE); + break; + default: + vty_out(vty, "%% mesh-group source del failed%s", VTY_NEWLINE); + } + + return result?CMD_WARNING:CMD_SUCCESS; +} + +DEFUN (no_ip_msdp_mesh_group_source, + no_ip_msdp_mesh_group_source_cmd, + "no ip msdp mesh-group WORD source", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group source\n" + "mesh group name\n" + "mesh group local address\n") +{ + return ip_no_msdp_mesh_group_source_cmd_worker(vty, argv[4]->arg); +} + +static int +ip_no_msdp_mesh_group_cmd_worker(struct vty *vty, const char *mg) +{ + enum pim_msdp_err result; + + result = pim_msdp_mg_del(mg); + switch (result) { + case PIM_MSDP_ERR_NONE: + break; + case PIM_MSDP_ERR_NO_MG: + vty_out(vty, "%% mesh-group does not exist%s", VTY_NEWLINE); + break; + default: + vty_out(vty, "%% mesh-group source del failed%s", VTY_NEWLINE); + } + + return result?CMD_WARNING:CMD_SUCCESS; +} + +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") +{ + return ip_no_msdp_mesh_group_cmd_worker(vty, argv[4]->arg); +} + +static void +ip_msdp_show_mesh_group(struct vty *vty, u_char uj) +{ + struct listnode *mbrnode; + struct pim_msdp_mg_mbr *mbr; + struct pim_msdp_mg *mg = 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_row = NULL; + + if (!mg) { + return; + } + + pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str)); + if (uj) { + json = json_object_new_object(); + /* currently there is only one mesh group but we should still make + * it a dict with mg-name as key */ + json_mg_row = json_object_new_object(); + json_object_string_add(json_mg_row, "name", mg->mesh_group_name); + json_object_string_add(json_mg_row, "source", src_str); + } else { + vty_out(vty, "Mesh group : %s%s", mg->mesh_group_name, VTY_NEWLINE); + vty_out(vty, " Source : %s%s", src_str, VTY_NEWLINE); + vty_out(vty, " Member State%s", VTY_NEWLINE); + } + + for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { + pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str)); + if (mbr->mp) { + state = mbr->mp->state; + } else { + state = PIM_MSDP_DISABLED; + } + pim_msdp_state_dump(state, state_str, sizeof(state_str)); + if (uj) { + json_row = json_object_new_object(); + json_object_string_add(json_row, "member", mbr_str); + json_object_string_add(json_row, "state", state_str); + json_object_object_add(json_mg_row, mbr_str, json_row); + } else { + vty_out(vty, " %-15s %11s%s", + mbr_str, state_str, VTY_NEWLINE); + } + } + + if (uj) { + json_object_object_add(json, mg->mesh_group_name, json_mg_row); + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } +} + +DEFUN (show_ip_msdp_mesh_group, + show_ip_msdp_mesh_group_cmd, + "show ip msdp mesh-group [json]", + SHOW_STR + IP_STR + MSDP_STR + "MSDP mesh-group information\n" + "JavaScript Object Notation\n") +{ + u_char uj = use_json(argc, argv); + ip_msdp_show_mesh_group(vty, uj); + + return CMD_SUCCESS; +} + static void ip_msdp_show_peers(struct vty *vty, u_char uj) { @@ -5251,40 +5521,148 @@ ip_msdp_show_peers(struct vty *vty, u_char uj) char state_str[PIM_MSDP_STATE_STRLEN]; char timebuf[PIM_MSDP_UPTIME_STRLEN]; int64_t now; + json_object *json = NULL; + json_object *json_row = NULL; + if (uj) { - // XXX: blah - return; + json = json_object_new_object(); } else { vty_out(vty, "Peer Local Mesh-group State Uptime%s", VTY_NEWLINE); - for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { - if (mp->state == PIM_MSDP_ESTABLISHED) { - now = pim_time_monotonic_sec(); - pim_time_uptime(timebuf, sizeof(timebuf), now - mp->uptime); - } else { - strcpy(timebuf, "-"); - } - pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str)); - pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str)); - pim_msdp_state_dump(mp->state, state_str, sizeof(state_str)); + } + + for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { + if (mp->state == PIM_MSDP_ESTABLISHED) { + now = pim_time_monotonic_sec(); + pim_time_uptime(timebuf, sizeof(timebuf), now - mp->uptime); + } else { + strcpy(timebuf, "-"); + } + pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str)); + pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str)); + pim_msdp_state_dump(mp->state, state_str, sizeof(state_str)); + if (uj) { + json_row = json_object_new_object(); + json_object_string_add(json_row, "peer", peer_str); + json_object_string_add(json_row, "local", local_str); + json_object_string_add(json_row, "meshGroupName", mp->mesh_group_name); + json_object_string_add(json_row, "state", state_str); + json_object_string_add(json_row, "upTime", timebuf); + json_object_object_add(json, peer_str, json_row); + } else { vty_out(vty, "%-15s %15s %16s %11s %8s%s", peer_str, local_str, mp->mesh_group_name, state_str, timebuf, VTY_NEWLINE); } } + + if (uj) { + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } } -DEFUN (show_ip_msdp_peer, - show_ip_msdp_peer_cmd, - "show ip msdp peer [json]", +static void +ip_msdp_show_peers_detail(struct vty *vty, const char *peer, u_char uj) +{ + struct listnode *mpnode; + struct pim_msdp_peer *mp; + char peer_str[INET_ADDRSTRLEN]; + char local_str[INET_ADDRSTRLEN]; + char state_str[PIM_MSDP_STATE_STRLEN]; + char timebuf[PIM_MSDP_UPTIME_STRLEN]; + char katimer[PIM_MSDP_TIMER_STRLEN]; + char crtimer[PIM_MSDP_TIMER_STRLEN]; + char holdtimer[PIM_MSDP_TIMER_STRLEN]; + int64_t now; + json_object *json = NULL; + json_object *json_row = NULL; + + if (uj) { + json = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { + pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str)); + if (strcmp(peer, "detail") && + strcmp(peer, peer_str)) + continue; + + if (mp->state == PIM_MSDP_ESTABLISHED) { + now = pim_time_monotonic_sec(); + pim_time_uptime(timebuf, sizeof(timebuf), now - mp->uptime); + } else { + strcpy(timebuf, "-"); + } + pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str)); + pim_msdp_state_dump(mp->state, state_str, sizeof(state_str)); + pim_time_timer_to_hhmmss(katimer, sizeof(katimer), mp->ka_timer); + pim_time_timer_to_hhmmss(crtimer, sizeof(crtimer), mp->cr_timer); + pim_time_timer_to_hhmmss(holdtimer, sizeof(holdtimer), mp->hold_timer); + + if (uj) { + json_row = json_object_new_object(); + json_object_string_add(json_row, "peer", peer_str); + json_object_string_add(json_row, "local", local_str); + json_object_string_add(json_row, "meshGroupName", mp->mesh_group_name); + json_object_string_add(json_row, "state", state_str); + json_object_string_add(json_row, "upTime", timebuf); + json_object_string_add(json_row, "keepAliveTime", katimer); + json_object_string_add(json_row, "connRetryTime", crtimer); + json_object_string_add(json_row, "holdTime", holdtimer); + json_object_string_add(json_row, "lastReset", mp->last_reset); + json_object_int_add(json_row, "connAttempts", mp->conn_attempts); + json_object_int_add(json_row, "establishedFlaps", mp->est_flaps); + json_object_int_add(json_row, "kaSent", mp->ka_tx_cnt); + json_object_int_add(json_row, "kaRcvd", mp->ka_rx_cnt); + json_object_int_add(json_row, "saSent", mp->sa_tx_cnt); + json_object_int_add(json_row, "saRcvd", mp->sa_rx_cnt); + json_object_object_add(json, peer_str, json_row); + } else { + vty_out(vty, "Peer : %s%s", peer_str, VTY_NEWLINE); + vty_out(vty, " Local : %s%s", local_str, VTY_NEWLINE); + vty_out(vty, " Mesh Group : %s%s", mp->mesh_group_name, VTY_NEWLINE); + vty_out(vty, " State : %s%s", state_str, VTY_NEWLINE); + vty_out(vty, " Uptime : %s%s", timebuf, VTY_NEWLINE); + + vty_out(vty, " Keepalive Time : %s%s", katimer, VTY_NEWLINE); + vty_out(vty, " Conn Retry Time : %s%s", crtimer, VTY_NEWLINE); + vty_out(vty, " Hold Time : %s%s", holdtimer, VTY_NEWLINE); + vty_out(vty, " Last Reset : %s%s", mp->last_reset, VTY_NEWLINE); + vty_out(vty, " Conn Attempts : %d%s", mp->conn_attempts, VTY_NEWLINE); + vty_out(vty, " Established Flaps: %d%s", mp->est_flaps, VTY_NEWLINE); + vty_out(vty, " Statistics :%s", VTY_NEWLINE); + vty_out(vty, " Sent Rcvd%s", VTY_NEWLINE); + vty_out(vty, " Keepalives : %10d %10d%s", + mp->ka_tx_cnt, mp->ka_rx_cnt, VTY_NEWLINE); + vty_out(vty, " SAs : %10d %10d%s", + mp->sa_tx_cnt, mp->sa_rx_cnt, VTY_NEWLINE); + vty_out(vty, "%s", VTY_NEWLINE); + } + } + + if (uj) { + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } +} + +DEFUN (show_ip_msdp_peer_detail, + show_ip_msdp_peer_detail_cmd, + "show ip msdp peer [detail|A.B.C.D] [json]", SHOW_STR IP_STR MSDP_STR "MSDP peer information\n" + "Detailed output\n" + "peer ip address\n" "JavaScript Object Notation\n") { u_char uj = use_json(argc, argv); - ip_msdp_show_peers(vty, uj); + if (argv[4]->arg) + ip_msdp_show_peers_detail(vty, argv[4]->arg, uj); + else + ip_msdp_show_peers(vty, uj); return CMD_SUCCESS; } @@ -5298,47 +5676,238 @@ ip_msdp_show_sa(struct vty *vty, u_char uj) char grp_str[INET_ADDRSTRLEN]; char rp_str[INET_ADDRSTRLEN]; char timebuf[PIM_MSDP_UPTIME_STRLEN]; - char spt_str[2]; + char spt_str[8]; int64_t now; + json_object *json = NULL; + json_object *json_group = NULL; + json_object *json_row = NULL; if (uj) { - // XXX: blah - return; + json = json_object_new_object(); } else { vty_out(vty, "Source Group RP SPT Uptime%s", VTY_NEWLINE); - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { - now = pim_time_monotonic_sec(); - pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); - pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); - if (sa->flags & PIM_MSDP_SAF_LOCAL) { - strcpy(rp_str, "local"); - strcpy(spt_str, "-"); + } + + for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + now = pim_time_monotonic_sec(); + pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); + pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); + if (sa->flags & PIM_MSDP_SAF_LOCAL) { + strcpy(rp_str, "local"); + strcpy(spt_str, "-"); + } else { + pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str)); + } + + if (uj) { + if (sa->up) { + strcpy(spt_str, "yes"); } else { - pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str)); - if (sa->up) { - strcpy(spt_str, "y"); - } else { - strcpy(spt_str, "n"); - } + strcpy(spt_str, "no"); + } + json_object_object_get_ex(json, grp_str, &json_group); + + if (!json_group) { + json_group = json_object_new_object(); + json_object_object_add(json, grp_str, json_group); + } + + json_row = json_object_new_object(); + json_object_string_add(json_row, "source", src_str); + json_object_string_add(json_row, "group", grp_str); + json_object_string_add(json_row, "rp", rp_str); + json_object_string_add(json_row, "sptSetup", spt_str); + json_object_string_add(json_row, "upTime", timebuf); + json_object_object_add(json_group, src_str, json_row); + } else { + if (sa->up) { + strcpy(spt_str, "y"); + } else { + strcpy(spt_str, "n"); } vty_out(vty, "%-15s %15s %15s %3s %8s%s", src_str, grp_str, rp_str, spt_str, timebuf, VTY_NEWLINE); } } + + + if (uj) { + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } } -DEFUN (show_ip_msdp_sa, - show_ip_msdp_sa_cmd, - "show ip msdp sa [json]", +static void +ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str, + const char *grp_str, struct vty *vty, + u_char uj, json_object *json) +{ + char rp_str[INET_ADDRSTRLEN]; + char peer_str[INET_ADDRSTRLEN]; + char timebuf[PIM_MSDP_UPTIME_STRLEN]; + char spt_str[8]; + char statetimer[PIM_MSDP_TIMER_STRLEN]; + int64_t now; + json_object *json_group = NULL; + json_object *json_row = NULL; + + now = pim_time_monotonic_sec(); + pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); + if (sa->flags & PIM_MSDP_SAF_LOCAL) { + strcpy(rp_str, "local"); + strcpy(peer_str, "-"); + strcpy(spt_str, "-"); + } else { + pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str)); + pim_inet4_dump("<peer?>", sa->peer, peer_str, sizeof(peer_str)); + if (sa->up) { + strcpy(spt_str, "yes"); + } else { + strcpy(spt_str, "no"); + } + } + pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer), sa->sa_state_timer); + if (uj) { + json_object_object_get_ex(json, grp_str, &json_group); + + if (!json_group) { + json_group = json_object_new_object(); + json_object_object_add(json, grp_str, json_group); + } + + json_row = json_object_new_object(); + json_object_string_add(json_row, "source", src_str); + json_object_string_add(json_row, "group", grp_str); + json_object_string_add(json_row, "rp", rp_str); + json_object_string_add(json_row, "sptSetup", spt_str); + json_object_string_add(json_row, "upTime", timebuf); + json_object_string_add(json_row, "stateTime", statetimer); + json_object_object_add(json_group, src_str, json_row); + } else { + vty_out(vty, "SA : %s%s", pim_str_sg_dump(&sa->sg), VTY_NEWLINE); + vty_out(vty, " RP : %s%s", rp_str, VTY_NEWLINE); + vty_out(vty, " Peer : %s%s", peer_str, VTY_NEWLINE); + vty_out(vty, " SPT Setup : %s%s", spt_str, VTY_NEWLINE); + vty_out(vty, " Uptime : %s%s", timebuf, VTY_NEWLINE); + vty_out(vty, " State Time : %s%s", statetimer, VTY_NEWLINE); + vty_out(vty, "%s", VTY_NEWLINE); + } +} + +static void +ip_msdp_show_sa_detail(struct vty *vty, u_char uj) +{ + struct listnode *sanode; + struct pim_msdp_sa *sa; + char src_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + json_object *json = NULL; + + if (uj) { + json = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); + ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json); + } + + if (uj) { + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } +} + +DEFUN (show_ip_msdp_sa_detail, + show_ip_msdp_sa_detail_cmd, + "show ip msdp sa detail [json]", SHOW_STR IP_STR MSDP_STR "MSDP active-source information\n" + "Detailed output\n" "JavaScript Object Notation\n") { u_char uj = use_json(argc, argv); - ip_msdp_show_sa(vty, uj); + ip_msdp_show_sa_detail(vty, uj); + + return CMD_SUCCESS; +} + +static void +ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj) +{ + struct listnode *sanode; + struct pim_msdp_sa *sa; + char src_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + json_object *json = NULL; + + if (uj) { + json = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); + if (!strcmp(addr, src_str) || !strcmp(addr, grp_str)) { + ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json); + } + } + + if (uj) { + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } +} + +static void +ip_msdp_show_sa_sg(struct vty *vty, const char *src, const char *grp, u_char uj) +{ + struct listnode *sanode; + struct pim_msdp_sa *sa; + char src_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + json_object *json = NULL; + + if (uj) { + json = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); + if (!strcmp(src, src_str) && !strcmp(grp, grp_str)) { + ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json); + } + } + + if (uj) { + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } +} + +DEFUN (show_ip_msdp_sa_sg, + show_ip_msdp_sa_sg_cmd, + "show ip msdp sa [A.B.C.D] [A.B.C.D] [json]", + SHOW_STR + IP_STR + MSDP_STR + "MSDP active-source information\n" + "source or group ip\n" + "group ip\n" + "JavaScript Object Notation\n") +{ + u_char uj = use_json(argc, argv); + if (argv[5]->arg) + ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj); + else if (argv[4]->arg) + ip_msdp_show_sa_addr(vty, argv[4]->arg, uj); + else + ip_msdp_show_sa(vty, uj); return CMD_SUCCESS; } @@ -5419,8 +5988,6 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_mroute_count_cmd); install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); - install_element (VIEW_NODE, &show_ip_msdp_peer_cmd); - install_element (VIEW_NODE, &show_ip_msdp_sa_cmd); install_element (VIEW_NODE, &show_debugging_pim_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); @@ -5508,4 +6075,15 @@ void pim_cmd_init() install_element (CONFIG_NODE, &debug_msdp_packets_cmd); install_element (CONFIG_NODE, &no_debug_msdp_packets_cmd); install_element (CONFIG_NODE, &undebug_msdp_packets_cmd); + install_element (CONFIG_NODE, &ip_msdp_peer_cmd); + install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element (CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); + install_element (CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element (CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); + install_element (CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element (CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); + install_element (VIEW_NODE, &show_ip_msdp_peer_detail_cmd); + install_element (VIEW_NODE, &show_ip_msdp_sa_detail_cmd); + install_element (VIEW_NODE, &show_ip_msdp_sa_sg_cmd); + install_element (VIEW_NODE, &show_ip_msdp_mesh_group_cmd); } diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index dd9300df8..2d09da4b5 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -63,6 +63,7 @@ #define MSDP_STR "MSDP information\n" #define DEBUG_MSDP_STR "MSDP protocol activity\n" #define DEBUG_MSDP_EVENTS_STR "MSDP protocol events\n" +#define DEBUG_MSDP_INTERNAL_STR "MSDP protocol internal\n" #define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n" void pim_cmd_init(void); diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index da37da699..a8d4c3404 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -42,5 +42,7 @@ DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info") DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info") DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info") DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer") -DEFINE_MTYPE(PIMD, PIM_MSDP_PEER_MG_NAME, "PIM MSDP peer mesh-group") +DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name") DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache") +DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group") +DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr") diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 434de0b19..0f47fc22b 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -41,7 +41,9 @@ DECLARE_MTYPE(PIM_BR) DECLARE_MTYPE(PIM_RP) DECLARE_MTYPE(PIM_FILTER_NAME) DECLARE_MTYPE(PIM_MSDP_PEER) -DECLARE_MTYPE(PIM_MSDP_PEER_MG_NAME) +DECLARE_MTYPE(PIM_MSDP_MG_NAME) DECLARE_MTYPE(PIM_MSDP_SA) +DECLARE_MTYPE(PIM_MSDP_MG) +DECLARE_MTYPE(PIM_MSDP_MG_MBR) #endif /* _QUAGGA_PIM_MEMORY_H */ diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 43e2e888f..76127245c 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -51,6 +51,9 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp); static void pim_msdp_enable(void); static void pim_msdp_sa_adv_timer_setup(bool start); 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 ******************************/ char * @@ -714,6 +717,10 @@ pim_msdp_peer_listen(struct pim_msdp_peer *mp) void pim_msdp_peer_established(struct pim_msdp_peer *mp) { + if (mp->state != PIM_MSDP_ESTABLISHED) { + ++mp->est_flaps; + } + mp->state = PIM_MSDP_ESTABLISHED; mp->uptime = pim_time_monotonic_sec(); @@ -740,6 +747,9 @@ void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state) { if (chg_state) { + if (mp->state == PIM_MSDP_ESTABLISHED) { + ++mp->est_flaps; + } mp->state = PIM_MSDP_INACTIVE; if (PIM_DEBUG_MSDP_EVENTS) { pim_msdp_peer_state_chg_log(mp); @@ -783,6 +793,7 @@ pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str) pim_msdp_peer_key_dump(mp, key_str, sizeof(key_str), false); zlog_debug("%s tcp reset %s", key_str, rc_str); + snprintf(mp->last_reset, sizeof(mp->last_reset), "%s", rc_str); } /* close the connection and transition to listening or connecting */ @@ -868,6 +879,7 @@ static void pim_msdp_peer_active_connect(struct pim_msdp_peer *mp) { int rc; + ++mp->conn_attempts; rc = pim_msdp_sock_connect(mp); if (PIM_DEBUG_MSDP_INTERNAL) { @@ -879,6 +891,7 @@ pim_msdp_peer_active_connect(struct pim_msdp_peer *mp) switch (rc) { case connect_error: + case -1: /* connect failed restart the connect-retry timer */ pim_msdp_peer_cr_timer_setup(mp, true /* start */); break; @@ -962,7 +975,7 @@ static void pim_msdp_addr2su(union sockunion *su, struct in_addr addr) /* 11.2.A1: create a new peer and transition state to listen or connecting */ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr, struct in_addr local_addr, - const char *mesh_group_name) + const char *mesh_group_name, struct pim_msdp_peer **mp_p) { struct pim_msdp_peer *mp; @@ -981,9 +994,10 @@ pim_msdp_peer_new(struct in_addr peer_addr, struct in_addr local_addr, /* XXX: originator_id setting needs to move to the mesh group */ msdp->originator_id = local_addr; pim_msdp_addr2su(&mp->su_local, mp->local); - mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_PEER_MG_NAME, mesh_group_name); + mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name); mp->state = PIM_MSDP_INACTIVE; mp->fd = -1; + strcpy(mp->last_reset, "-"); /* higher IP address is listener */ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) { mp->flags |= PIM_MSDP_PEERF_LISTENER; @@ -1012,6 +1026,9 @@ pim_msdp_peer_new(struct in_addr peer_addr, struct in_addr local_addr, } else { pim_msdp_peer_connect(mp); } + if (mp_p) { + *mp_p = mp; + } return PIM_MSDP_ERR_NONE; } @@ -1027,16 +1044,34 @@ pim_msdp_peer_find(struct in_addr peer_addr) /* add peer configuration if it doesn't already exist */ enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr, struct in_addr local_addr, - const char *mesh_group_name) + const char *mesh_group_name, struct pim_msdp_peer **mp_p) { struct pim_msdp_peer *mp; + if (mp_p) { + *mp_p = NULL; + } + + if (peer_addr.s_addr == local_addr.s_addr) { + /* skip session setup if config is invalid */ + if (PIM_DEBUG_MSDP_EVENTS) { + char peer_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("<peer?>", peer_addr, peer_str, sizeof(peer_str)); + zlog_debug("%s add skipped as DIP=SIP", peer_str); + } + return PIM_MSDP_ERR_SIP_EQ_DIP; + } + mp = pim_msdp_peer_find(peer_addr); if (mp) { + if (mp_p) { + *mp_p = mp; + } return PIM_MSDP_ERR_PEER_EXISTS; } - return pim_msdp_peer_new(peer_addr, local_addr, mesh_group_name); + return pim_msdp_peer_new(peer_addr, local_addr, mesh_group_name, mp_p); } /* release all mem associated with a peer */ @@ -1052,22 +1087,15 @@ pim_msdp_peer_free(struct pim_msdp_peer *mp) } if (mp->mesh_group_name) { - XFREE(MTYPE_PIM_MSDP_PEER_MG_NAME, mp->mesh_group_name); + XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name); } XFREE(MTYPE_PIM_MSDP_PEER, mp); } /* delete the peer config */ -enum pim_msdp_err -pim_msdp_peer_del(struct in_addr peer_addr) +static enum pim_msdp_err +pim_msdp_peer_do_del(struct pim_msdp_peer *mp) { - struct pim_msdp_peer *mp; - - mp = pim_msdp_peer_find(peer_addr); - if (!mp) { - return PIM_MSDP_ERR_NO_PEER; - } - /* stop the tcp connection and shutdown all timers */ pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */); @@ -1088,6 +1116,19 @@ pim_msdp_peer_del(struct in_addr peer_addr) return PIM_MSDP_ERR_NONE; } +enum pim_msdp_err +pim_msdp_peer_del(struct in_addr peer_addr) +{ + struct pim_msdp_peer *mp; + + mp = pim_msdp_peer_find(peer_addr); + if (!mp) { + return PIM_MSDP_ERR_NO_PEER; + } + + return pim_msdp_peer_do_del(mp); +} + /* peer hash and peer list helpers */ static unsigned int pim_msdp_peer_hash_key_make(void *p) @@ -1120,21 +1161,317 @@ pim_msdp_peer_comp(const void *p1, const void *p2) return 0; } +/************************** Mesh group management **************************/ +static void +pim_msdp_mg_free(struct pim_msdp_mg *mg) +{ + /* 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)) { + return; + } + + if (PIM_DEBUG_MSDP_EVENTS) { + zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name); + } + if (mg->mesh_group_name) + XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name); + XFREE(MTYPE_PIM_MSDP_MG, mg); + + msdp->mg = NULL; +} + +static struct pim_msdp_mg * +pim_msdp_mg_new(const char *mesh_group_name) +{ + struct pim_msdp_mg *mg; + + mg = XCALLOC(MTYPE_PIM_MSDP_MG, sizeof(*mg)); + if (!mg) { + zlog_err("%s: PIM XCALLOC(%zu) failure", + __PRETTY_FUNCTION__, sizeof(*mg)); + return NULL; + } + + mg->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name); + mg->mbr_list = list_new(); + mg->mbr_list->del = (void (*)(void *))pim_msdp_mg_mbr_free; + mg->mbr_list->cmp = (int (*)(void *, void *))pim_msdp_mg_mbr_comp; + + if (PIM_DEBUG_MSDP_EVENTS) { + zlog_debug("MSDP mesh-group %s created", mg->mesh_group_name); + } + return mg; +} + +enum pim_msdp_err +pim_msdp_mg_del(const char *mesh_group_name) +{ + struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg_mbr *mbr; + + if (!mg || 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(mg); + return PIM_MSDP_ERR_NONE; +} + +static enum pim_msdp_err +pim_msdp_mg_add(const char *mesh_group_name) +{ + if (msdp->mg) { + if (!strcmp(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; + } + + msdp->mg = pim_msdp_mg_new(mesh_group_name); + if (!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; + const struct pim_msdp_mg_mbr *mbr2 = p2; + + if (ntohl(mbr1->mbr_ip.s_addr) < ntohl(mbr2->mbr_ip.s_addr)) + return -1; + + if (ntohl(mbr1->mbr_ip.s_addr) > ntohl(mbr2->mbr_ip.s_addr)) + return 1; + + return 0; +} + +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 in_addr mbr_ip) +{ + struct pim_msdp_mg_mbr *mbr; + struct listnode *mbr_node; + + if (!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(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(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(mesh_group_name); + if (rc != PIM_MSDP_ERR_NONE) { + return rc; + } + + mg = msdp->mg; + mbr = pim_msdp_mg_mbr_find(mbr_ip); + if (mbr) { + return PIM_MSDP_ERR_MG_MBR_EXISTS; + } + + mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr)); + if (!mbr) { + zlog_err("%s: PIM XCALLOC(%zu) failure", + __PRETTY_FUNCTION__, sizeof(*mbr)); + /* if there are no references to the mg free it */ + pim_msdp_mg_free(mg); + return PIM_MSDP_ERR_OOM; + } + 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(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) +{ + /* Delete active peer session if any */ + if (mbr->mp) { + pim_msdp_peer_do_del(mbr->mp); + } + + listnode_delete(mg->mbr_list, mbr); + 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 deleted", mg->mesh_group_name, ip_str); + } + pim_msdp_mg_mbr_free(mbr); + if (mg->mbr_cnt) { + --mg->mbr_cnt; + } +} + +enum pim_msdp_err +pim_msdp_mg_mbr_del(const char *mesh_group_name, struct in_addr mbr_ip) +{ + struct pim_msdp_mg_mbr *mbr; + struct pim_msdp_mg *mg = msdp->mg; + + if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) { + return PIM_MSDP_ERR_NO_MG; + } + + mbr = pim_msdp_mg_mbr_find(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(mg); + + return PIM_MSDP_ERR_NONE; +} + +static void +pim_msdp_mg_src_do_del(void) +{ + struct pim_msdp_mg_mbr *mbr; + struct listnode *mbr_node; + struct pim_msdp_mg *mg = msdp->mg; + + /* SIP is being removed - tear down all active peer sessions */ + for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) { + if (mbr->mp) { + pim_msdp_peer_do_del(mbr->mp); + mbr->mp = NULL; + } + } + if (PIM_DEBUG_MSDP_EVENTS) { + zlog_debug("MSDP mesh-group %s src cleared", mg->mesh_group_name); + } +} + +enum pim_msdp_err +pim_msdp_mg_src_del(const char *mesh_group_name) +{ + struct pim_msdp_mg *mg = 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(); + /* if there are no references to the mg free it */ + pim_msdp_mg_free(mg); + } + return PIM_MSDP_ERR_NONE; +} + +enum pim_msdp_err +pim_msdp_mg_src_add(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(mesh_group_name); + return PIM_MSDP_ERR_NONE; + } + + rc = pim_msdp_mg_add(mesh_group_name); + if (rc != PIM_MSDP_ERR_NONE) { + return rc; + } + + mg = msdp->mg; + if (mg->src_ip.s_addr != INADDR_ANY) { + pim_msdp_mg_src_do_del(); + } + mg->src_ip = src_ip; + + for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) { + pim_msdp_peer_add(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 vty *vty) { - struct listnode *mpnode; - struct pim_msdp_peer *mp; - char peer_str[INET_ADDRSTRLEN]; - char local_str[INET_ADDRSTRLEN]; + struct listnode *mbrnode; + struct pim_msdp_mg_mbr *mbr; + struct pim_msdp_mg *mg = msdp->mg; + char mbr_str[INET_ADDRSTRLEN]; + char src_str[INET_ADDRSTRLEN]; int count = 0; - for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { - pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str)); - pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str)); - vty_out(vty, "ip msdp peer %s source %s%s", - peer_str, local_str, VTY_NEWLINE); + if (!mg) { + return count; + } + + if (mg->src_ip.s_addr != INADDR_ANY) { + pim_inet4_dump("<src?>", mg->src_ip, src_str, sizeof(src_str)); + vty_out(vty, "ip msdp mesh-group %s source %s%s", + mg->mesh_group_name, src_str, VTY_NEWLINE); + ++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, "ip msdp mesh-group %s member %s%s", + mg->mesh_group_name, mbr_str, VTY_NEWLINE); ++count; } return count; diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 5e13b33b5..4809749b9 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -46,12 +46,17 @@ enum pim_msdp_err { PIM_MSDP_ERR_PEER_EXISTS = -2, PIM_MSDP_ERR_MAX_MESH_GROUPS = -3, PIM_MSDP_ERR_NO_PEER = -4, + PIM_MSDP_ERR_MG_MBR_EXISTS = -5, + PIM_MSDP_ERR_NO_MG = -6, + PIM_MSDP_ERR_NO_MG_MBR = -7, + PIM_MSDP_ERR_SIP_EQ_DIP = -8, }; #define PIM_MSDP_STATE_STRLEN 16 #define PIM_MSDP_PEER_KEY_STRLEN 80 #define PIM_MSDP_SA_KEY_STRLEN 80 #define PIM_MSDP_UPTIME_STRLEN 80 +#define PIM_MSDP_TIMER_STRLEN 12 #define PIM_MSDP_TCP_PORT 639 #define PIM_MSDP_SOCKET_SNDBUF_SIZE 65536 @@ -123,6 +128,12 @@ struct pim_msdp_peer { struct thread *t_write; /* stats */ + uint32_t conn_attempts; + uint32_t est_flaps; +#define PIM_MSDP_PEER_LAST_RESET_STR 20 + char last_reset[PIM_MSDP_PEER_LAST_RESET_STR]; + + /* packet stats */ uint32_t ka_tx_cnt; uint32_t sa_tx_cnt; uint32_t ka_rx_cnt; @@ -133,6 +144,19 @@ struct pim_msdp_peer { int64_t uptime; }; +struct pim_msdp_mg_mbr { + struct in_addr mbr_ip; + struct pim_msdp_peer *mp; +}; + +/* PIM MSDP mesh-group */ +struct pim_msdp_mg { + char *mesh_group_name; + struct in_addr src_ip; + uint32_t mbr_cnt; + struct list *mbr_list; +}; + enum pim_msdp_flags { PIM_MSDPF_NONE = 0, PIM_MSDPF_ENABLE = (1 << 0), @@ -166,6 +190,9 @@ struct pim_msdp { struct stream *work_obuf; struct in_addr originator_id; + + /* currently only one mesh-group is supported - so just stash it here */ + struct pim_msdp_mg *mg; }; #define PIM_MSDP_PEER_READ_ON(mp) THREAD_READ_ON(msdp->master, mp->t_read, pim_msdp_read, mp, mp->fd); @@ -177,7 +204,7 @@ struct pim_msdp { extern struct pim_msdp *msdp; void pim_msdp_init(struct thread_master *master); void pim_msdp_exit(void); -enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer, struct in_addr local, const char *mesh_group_name); +enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer, struct in_addr local, const char *mesh_group_name, struct pim_msdp_peer **mp_p); enum pim_msdp_err pim_msdp_peer_del(struct in_addr peer_addr); char *pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf, int buf_size); struct pim_msdp_peer *pim_msdp_peer_find(struct in_addr peer_addr); @@ -197,4 +224,9 @@ void pim_msdp_i_am_rp_changed(void); bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp); void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up); void pim_msdp_up_xg_del(struct prefix_sg *sg); +enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name, struct in_addr mbr_ip); +enum pim_msdp_err pim_msdp_mg_mbr_del(const char *mesh_group_name, struct in_addr mbr_ip); +enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name); +enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name, struct in_addr src_ip); +enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name); #endif diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index d336051f2..d7251e034 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -53,6 +53,10 @@ pim_debug_config_write (struct vty *vty) vty_out(vty, "debug msdp packets%s", VTY_NEWLINE); ++writes; } + if (PIM_DEBUG_MSDP_INTERNAL) { + vty_out(vty, "debug msdp internal%s", VTY_NEWLINE); + ++writes; + } if (PIM_DEBUG_IGMP_EVENTS) { vty_out(vty, "debug igmp events%s", VTY_NEWLINE); ++writes; |