From 09f267ec95de6da5ae8282ae9f69485f8649d9ad Mon Sep 17 00:00:00 2001 From: Francois Dumontet Date: Tue, 31 May 2022 17:40:39 +0200 Subject: [PATCH] bmp: add a interface source to bmp connect command With current release, forcin the source ip address when setting up a BMP connection is not possible. The need is to add an extra parameter for the following vty command: router bgp 65500 bmp targets AAA bmp connect 2.2.2.2 port 666 min-retry 100 max-retry 700 bmp connect 2:2::2:2 port 666 min-retry 100 max-retry 700 [source-interface lo1] Signed-off-by: Francois Dumontet --- bgpd/bgp_bmp.c | 103 ++++++++++++++++++++++++++++++++++++++++----- bgpd/bgp_bmp.h | 2 + bgpd/bgp_network.c | 2 +- bgpd/bgp_network.h | 2 + doc/user/bmp.rst | 6 ++- 5 files changed, 102 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 109f70f78f..e891f4ba42 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -50,6 +50,7 @@ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_trace.h" +#include "bgpd/bgp_network.h" static void bmp_close(struct bmp *bmp); static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp); @@ -1763,6 +1764,7 @@ static void bmp_active_put(struct bmp_active *ba) if (ba->socket != -1) close(ba->socket); + XFREE(MTYPE_TMP, ba->ifsrc); XFREE(MTYPE_TMP, ba->hostname); XFREE(MTYPE_BMP_ACTIVE, ba); } @@ -1773,8 +1775,37 @@ static void bmp_active_connect(struct bmp_active *ba) { enum connect_result res; char buf[SU_ADDRSTRLEN]; + struct interface *ifp; + vrf_id_t vrf_id = VRF_DEFAULT; + int res_bind; for (; ba->addrpos < ba->addrtotal; ba->addrpos++) { + if (ba->ifsrc) { + if (ba->targets && ba->targets->bgp) + vrf_id = ba->targets->bgp->vrf_id; + + /* find interface and related */ + /* address with same family */ + ifp = if_lookup_by_name(ba->ifsrc, vrf_id); + if (!ifp) { + zlog_warn("bmp[%s]: failed to find interface", + ba->ifsrc); + continue; + } + + if (bgp_update_address(ifp, &ba->addrs[ba->addrpos], + &ba->addrsrc)){ + zlog_warn("bmp[%s]: failed to find matching address", + ba->ifsrc); + continue; + } + zlog_info("bmp[%s]: selected source address : %s", + ba->ifsrc, + sockunion2str(&ba->addrsrc, + buf, + SU_ADDRSTRLEN)); + } + ba->socket = sockunion_socket(&ba->addrs[ba->addrpos]); if (ba->socket < 0) { zlog_warn("bmp[%s]: failed to create socket", @@ -1783,6 +1814,23 @@ static void bmp_active_connect(struct bmp_active *ba) } set_nonblocking(ba->socket); + + if (!sockunion_is_null(&ba->addrsrc)) { + res_bind = sockunion_bind(ba->socket, &ba->addrsrc, 0, + &ba->addrsrc); + if (res_bind < 0) { + sockunion2str(&ba->addrsrc, buf, sizeof(buf)); + zlog_warn( + "bmp[%s]: no bind currently to source address %s:%d", + ba->hostname, buf, ba->port); + close(ba->socket); + ba->socket = -1; + sockunion_init(&ba->addrsrc); + continue; + } + } + + res = sockunion_connect(ba->socket, &ba->addrs[ba->addrpos], htons(ba->port), 0); switch (res) { @@ -1793,10 +1841,19 @@ static void bmp_active_connect(struct bmp_active *ba) ba->hostname, buf, ba->port); close(ba->socket); ba->socket = -1; + sockunion_init(&ba->addrsrc); continue; case connect_success: + sockunion2str(&ba->addrs[ba->addrpos], buf, + sizeof(buf)); + zlog_info("bmp[%s]: connected to %s:%d", + ba->hostname, buf, ba->port); break; case connect_in_progress: + sockunion2str(&ba->addrs[ba->addrpos], buf, + sizeof(buf)); + zlog_warn("bmp[%s]: connect in progress %s:%d", + ba->hostname, buf, ba->port); bmp_active_setup(ba); return; } @@ -2041,7 +2098,7 @@ DEFPY(no_bmp_listener_main, DEFPY(bmp_connect, bmp_connect_cmd, - "[no] bmp connect HOSTNAME port (1-65535) {min-retry (100-86400000)|max-retry (100-86400000)}", + "[no] bmp connect HOSTNAME port (1-65535) {min-retry (100-86400000)|max-retry (100-86400000)} [source-interface ]", NO_STR BMP_STR "Actively establish connection to monitoring station\n" @@ -2051,7 +2108,9 @@ DEFPY(bmp_connect, "Minimum connection retry interval\n" "Minimum connection retry interval (milliseconds)\n" "Maximum connection retry interval\n" - "Maximum connection retry interval (milliseconds)\n") + "Maximum connection retry interval (milliseconds)\n" + "Source interface to use\n" + "Define an interface\n") { VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt); struct bmp_active *ba; @@ -2062,11 +2121,21 @@ DEFPY(bmp_connect, vty_out(vty, "%% No such active connection found\n"); return CMD_WARNING; } + /* connection deletion need same hostname port and interface */ + if (ba->ifsrc || srcif) + if ((!ba->ifsrc) || (!srcif) || + !strcmp(ba->ifsrc, srcif)) { + vty_out(vty, + "%% No such active connection found\n"); + return CMD_WARNING; + } bmp_active_put(ba); return CMD_SUCCESS; } ba = bmp_active_get(bt, hostname, port); + if (srcif) + ba->ifsrc = XSTRDUP(MTYPE_TMP, srcif); if (min_retry_str) ba->minretry = min_retry; if (max_retry_str) @@ -2309,7 +2378,7 @@ DEFPY(show_bmp, vty_out(vty, "\n Outbound connections:\n"); tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); - ttable_add_row(tt, "remote|state||timer"); + ttable_add_row(tt, "remote|state||timer|local"); ttable_rowseps(tt, 0, BOTTOM, true, '-'); frr_each (bmp_actives, &bt->actives, ba) { const char *state_str = "?"; @@ -2318,9 +2387,13 @@ DEFPY(show_bmp, peer_uptime(ba->bmp->t_up.tv_sec, uptime, sizeof(uptime), false, NULL); - ttable_add_row(tt, "%s:%d|Up|%s|%s", + ttable_add_row(tt, "%s:%d|Up|%s|%s|%s", ba->hostname, ba->port, - ba->bmp->remote, uptime); + ba->bmp->remote, uptime, + sockunion2str( + &ba->addrsrc, + buf, + SU_ADDRSTRLEN)); continue; } @@ -2340,11 +2413,15 @@ DEFPY(show_bmp, state_str = "Resolving"; } - ttable_add_row(tt, "%s:%d|%s|%s|%s", + sockunion2str(&ba->addrsrc, + buf, + SU_ADDRSTRLEN); + ttable_add_row(tt, "%s:%d|%s|%s|%s|%s", ba->hostname, ba->port, state_str, ba->last_err ? ba->last_err : "", - uptime); + uptime, + buf); continue; } out = ttable_dump(tt, "\n"); @@ -2432,10 +2509,16 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) sockunion2str(&bl->addr, buf, SU_ADDRSTRLEN), bl->port); - frr_each (bmp_actives, &bt->actives, ba) - vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u\n", - ba->hostname, ba->port, ba->minretry, ba->maxretry); + frr_each (bmp_actives, &bt->actives, ba) { + vty_out(vty, " bmp connect %s port %u min-retry %u max-retry %u", + ba->hostname, ba->port, + ba->minretry, ba->maxretry); + if (ba->ifsrc) + vty_out(vty, " source-interface %s\n", ba->ifsrc); + else + vty_out(vty, "\n"); + } vty_out(vty, " exit\n"); } diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index 899840e582..1693b443ef 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -179,6 +179,8 @@ struct bmp_active { char *hostname; int port; unsigned minretry, maxretry; + char *ifsrc; + union sockunion addrsrc; struct resolver_query resq; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 77e2a0f53f..b68e2931d8 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -632,7 +632,7 @@ static char *bgp_get_bound_name(struct peer *peer) return peer->bgp->name; } -static int bgp_update_address(struct interface *ifp, const union sockunion *dst, +int bgp_update_address(struct interface *ifp, const union sockunion *dst, union sockunion *addr) { struct prefix *p, *sel, d; diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 22e34110bc..7420397a93 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -45,5 +45,7 @@ extern int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p); extern int bgp_md5_set(struct peer *); extern int bgp_md5_unset(struct peer *); extern int bgp_set_socket_ttl(struct peer *, int fd); +extern int bgp_update_address(struct interface *ifp, const union sockunion *dst, + union sockunion *addr); #endif /* _QUAGGA_BGP_NETWORK_H */ diff --git a/doc/user/bmp.rst b/doc/user/bmp.rst index f925910d45..764584f89c 100644 --- a/doc/user/bmp.rst +++ b/doc/user/bmp.rst @@ -108,13 +108,15 @@ BMP session configuration Inside a ``bmp targets`` block, the following commands control session establishment: -.. clicmd:: bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC} + +.. clicmd:: bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC} [source-interface WORD] Add/remove an active outbound BMP session. HOSTNAME is resolved via DNS, if multiple addresses are returned they are tried in nondeterministic order. Only one connection will be established even if multiple addresses are returned. ``min-retry`` and ``max-retry`` specify (in milliseconds) - bounds for exponential backoff. + bounds for exponential backoff. ``source-interface`` is the local interface on + which the connection has to bind. .. warning:: -- 2.39.5