pimd: MSDP SA forwarding

* If the MSDP peer receives the SA from a non-RPF peer towards the
originating RP, it will drop the message.
* SA messages are forwarded away from the RP address only.
* SA messages are not forwarded within the mesh group.
* Preventing the MSDP connection from being dropped due to RPF check
failure (RFC3618, section 13 "MSDP Error Handling")

Signed-off-by: Adriano Marto Reis <adrianomarto@gmail.com>
Signed-off-by: Adriano Reis <areis@barrukka.local>
This commit is contained in:
Adriano Marto Reis 2020-07-10 08:56:24 +10:00 committed by Donald Sharp
parent 002bac8b5b
commit 9fbd9fc48f
4 changed files with 58 additions and 13 deletions

View File

@ -9694,7 +9694,7 @@ static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
return ret; return ret;
} }
DEFUN_HIDDEN (ip_msdp_peer, DEFUN (ip_msdp_peer,
ip_msdp_peer_cmd, ip_msdp_peer_cmd,
"ip msdp peer A.B.C.D source A.B.C.D", "ip msdp peer A.B.C.D source A.B.C.D",
IP_STR IP_STR
@ -9735,7 +9735,7 @@ static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
} }
DEFUN_HIDDEN (no_ip_msdp_peer, DEFUN (no_ip_msdp_peer,
no_ip_msdp_peer_cmd, no_ip_msdp_peer_cmd,
"no ip msdp peer A.B.C.D", "no ip msdp peer A.B.C.D",
NO_STR NO_STR

View File

@ -423,6 +423,7 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp,
sa->sg_str); sa->sg_str);
} }
/* send an immediate SA update to peers */ /* send an immediate SA update to peers */
sa->rp = pim->msdp.originator_id;
pim_msdp_pkt_sa_tx_one(sa); pim_msdp_pkt_sa_tx_one(sa);
} }
sa->flags &= ~PIM_MSDP_SAF_STALE; sa->flags &= ~PIM_MSDP_SAF_STALE;
@ -721,10 +722,18 @@ static int pim_msdp_sa_comp(const void *p1, const void *p2)
/* XXX: this can use a bit of refining and extensions */ /* XXX: this can use a bit of refining and extensions */
bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp) bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp)
{ {
struct pim_nexthop nexthop;
if (mp->peer.s_addr == rp.s_addr) { if (mp->peer.s_addr == rp.s_addr) {
return true; return true;
} }
/* check if the MSDP peer is the nexthop for the RP */
if (pim_nexthop_lookup(mp->pim, &nexthop, rp, 0)
&& nexthop.mrib_nexthop_addr.u.prefix4.s_addr == mp->peer.s_addr) {
return true;
}
return false; return false;
} }

View File

@ -348,7 +348,8 @@ static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
} }
} }
static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt) static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
struct in_addr rp)
{ {
int curr_tlv_ecnt; int curr_tlv_ecnt;
@ -361,7 +362,7 @@ static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt)
stream_putw(pim->msdp.work_obuf, stream_putw(pim->msdp.work_obuf,
PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt)); PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt); stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
stream_put_ipv4(pim->msdp.work_obuf, pim->msdp.originator_id.s_addr); stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
return local_cnt; return local_cnt;
} }
@ -387,7 +388,8 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
zlog_debug(" sa gen %d", local_cnt); zlog_debug(" sa gen %d", local_cnt);
} }
local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt); local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
pim->msdp.originator_id);
for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) { if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
@ -408,7 +410,8 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
zlog_debug(" sa gen for remainder %d", zlog_debug(" sa gen for remainder %d",
local_cnt); local_cnt);
} }
local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt); local_cnt = pim_msdp_pkt_sa_fill_hdr(
pim, local_cnt, pim->msdp.originator_id);
} }
} }
@ -441,7 +444,7 @@ void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa) void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
{ {
pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */); pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
pim_msdp_pkt_sa_fill_one(sa); pim_msdp_pkt_sa_fill_one(sa);
pim_msdp_pkt_sa_push(sa->pim, NULL); pim_msdp_pkt_sa_push(sa->pim, NULL);
pim_msdp_pkt_sa_tx_done(sa->pim); pim_msdp_pkt_sa_tx_done(sa->pim);
@ -454,6 +457,24 @@ void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
pim_msdp_pkt_sa_tx_done(mp->pim); pim_msdp_pkt_sa_tx_done(mp->pim);
} }
void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
struct in_addr rp, struct prefix_sg sg)
{
struct pim_msdp_sa sa;
/* Fills the SA header. */
pim_msdp_pkt_sa_fill_hdr(mp->pim, 1, rp);
/* Fills the message contents. */
sa.pim = mp->pim;
sa.sg = sg;
pim_msdp_pkt_sa_fill_one(&sa);
/* Pushes the message. */
pim_msdp_pkt_sa_push(sa.pim, mp);
pim_msdp_pkt_sa_tx_done(sa.pim);
}
static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp) static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
{ {
pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx"); pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
@ -473,6 +494,8 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
{ {
int prefix_len; int prefix_len;
struct prefix_sg sg; struct prefix_sg sg;
struct listnode *peer_node;
struct pim_msdp_peer *peer;
/* just throw away the three reserved bytes */ /* just throw away the three reserved bytes */
stream_get3(mp->ibuf); stream_get3(mp->ibuf);
@ -493,6 +516,18 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
zlog_debug(" sg %s", pim_str_sg_dump(&sg)); zlog_debug(" sg %s", pim_str_sg_dump(&sg));
} }
pim_msdp_sa_ref(mp->pim, mp, &sg, rp); pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
/* Forwards the SA to the peers that are not in the RPF to the RP nor in
* the same mesh group as the peer from which we received the message.
* If the message group is not set, i.e. "default", then we assume that
* the message must be forwarded.*/
for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
if (!pim_msdp_peer_rpf_check(peer, rp)
&& (strcmp(mp->mesh_group_name, peer->mesh_group_name)
|| !strcmp(mp->mesh_group_name, "default"))) {
pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
}
}
} }
static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len) static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
@ -510,10 +545,9 @@ static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
entry_cnt = stream_getc(mp->ibuf); entry_cnt = stream_getc(mp->ibuf);
/* some vendors include the actual multicast data in the tlv (at the /* some vendors include the actual multicast data in the tlv (at the
* end). * end). we will ignore such data. in the future we may consider pushing
* we will ignore such data. in the future we may consider pushing it * it down the RPT
* down */
* the RPT */
if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) { if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
pim_msdp_pkt_rxed_with_fatal_error(mp); pim_msdp_pkt_rxed_with_fatal_error(mp);
return; return;
@ -526,6 +560,8 @@ static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str); zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
} }
pim_msdp_peer_pkt_rxed(mp);
if (!pim_msdp_peer_rpf_check(mp, rp)) { if (!pim_msdp_peer_rpf_check(mp, rp)) {
/* if peer-RPF check fails don't process the packet any further /* if peer-RPF check fails don't process the packet any further
*/ */
@ -535,8 +571,6 @@ static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
return; return;
} }
pim_msdp_peer_pkt_rxed(mp);
/* update SA cache */ /* update SA cache */
for (i = 0; i < entry_cnt; ++i) { for (i = 0; i < entry_cnt; ++i) {
pim_msdp_pkt_sa_rx_one(mp, rp); pim_msdp_pkt_sa_rx_one(mp, rp);

View File

@ -67,5 +67,7 @@ int pim_msdp_read(struct thread *thread);
void pim_msdp_pkt_sa_tx(struct pim_instance *pim); void pim_msdp_pkt_sa_tx(struct pim_instance *pim);
void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa);
void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp);
void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
struct in_addr rp, struct prefix_sg sg);
#endif #endif