mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 16:04:49 +00:00
Merge pull request #7748 from adrianomarto/bgp-listen-on-multiple-addresses
BGP daemon listen for connections on multiple addresses
This commit is contained in:
commit
6f860c4618
@ -253,6 +253,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
|
|||||||
|
|
||||||
bf_free(bm->rd_idspace);
|
bf_free(bm->rd_idspace);
|
||||||
list_delete(&bm->bgp);
|
list_delete(&bm->bgp);
|
||||||
|
list_delete(&bm->addresses);
|
||||||
|
|
||||||
bgp_lp_finish();
|
bgp_lp_finish();
|
||||||
|
|
||||||
@ -404,12 +405,16 @@ int main(int argc, char **argv)
|
|||||||
int tmp_port;
|
int tmp_port;
|
||||||
|
|
||||||
int bgp_port = BGP_PORT_DEFAULT;
|
int bgp_port = BGP_PORT_DEFAULT;
|
||||||
char *bgp_address = NULL;
|
struct list *addresses = list_new();
|
||||||
int no_fib_flag = 0;
|
int no_fib_flag = 0;
|
||||||
int no_zebra_flag = 0;
|
int no_zebra_flag = 0;
|
||||||
int skip_runas = 0;
|
int skip_runas = 0;
|
||||||
int instance = 0;
|
int instance = 0;
|
||||||
int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
|
int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
|
||||||
|
char *address;
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
addresses->cmp = (int (*)(void *, void *))strcmp;
|
||||||
|
|
||||||
frr_preinit(&bgpd_di, argc, argv);
|
frr_preinit(&bgpd_di, argc, argv);
|
||||||
frr_opt_add(
|
frr_opt_add(
|
||||||
@ -463,7 +468,7 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'l':
|
case 'l':
|
||||||
bgp_address = optarg;
|
listnode_add_sort_nodup(addresses, optarg);
|
||||||
/* listenon implies -n */
|
/* listenon implies -n */
|
||||||
/* fallthru */
|
/* fallthru */
|
||||||
case 'n':
|
case 'n':
|
||||||
@ -493,11 +498,10 @@ int main(int argc, char **argv)
|
|||||||
memset(&bgpd_privs, 0, sizeof(bgpd_privs));
|
memset(&bgpd_privs, 0, sizeof(bgpd_privs));
|
||||||
|
|
||||||
/* BGP master init. */
|
/* BGP master init. */
|
||||||
bgp_master_init(frr_init(), buffer_size);
|
bgp_master_init(frr_init(), buffer_size, addresses);
|
||||||
bm->port = bgp_port;
|
bm->port = bgp_port;
|
||||||
if (bgp_port == 0)
|
if (bgp_port == 0)
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
bm->address = bgp_address;
|
|
||||||
if (no_fib_flag || no_zebra_flag)
|
if (no_fib_flag || no_zebra_flag)
|
||||||
bgp_option_set(BGP_OPT_NO_FIB);
|
bgp_option_set(BGP_OPT_NO_FIB);
|
||||||
if (no_zebra_flag)
|
if (no_zebra_flag)
|
||||||
@ -513,8 +517,16 @@ int main(int argc, char **argv)
|
|||||||
/* BGP related initialization. */
|
/* BGP related initialization. */
|
||||||
bgp_init((unsigned short)instance);
|
bgp_init((unsigned short)instance);
|
||||||
|
|
||||||
snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo), ", bgp@%s:%d",
|
if (list_isempty(bm->addresses)) {
|
||||||
(bm->address ? bm->address : "<all>"), bm->port);
|
snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo),
|
||||||
|
", bgp@<all>:%d", bm->port);
|
||||||
|
} else {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
|
||||||
|
snprintf(bgpd_di.startinfo + strlen(bgpd_di.startinfo),
|
||||||
|
sizeof(bgpd_di.startinfo)
|
||||||
|
- strlen(bgpd_di.startinfo),
|
||||||
|
", bgp@%s:%d", address, bm->port);
|
||||||
|
}
|
||||||
|
|
||||||
frr_config_fork();
|
frr_config_fork();
|
||||||
/* must be called after fork() */
|
/* must be called after fork() */
|
||||||
|
30
bgpd/bgpd.c
30
bgpd/bgpd.c
@ -121,12 +121,20 @@ extern struct zclient *zclient;
|
|||||||
static int bgp_check_main_socket(bool create, struct bgp *bgp)
|
static int bgp_check_main_socket(bool create, struct bgp *bgp)
|
||||||
{
|
{
|
||||||
static int bgp_server_main_created;
|
static int bgp_server_main_created;
|
||||||
|
struct listnode *node;
|
||||||
|
char *address;
|
||||||
|
|
||||||
if (create) {
|
if (create) {
|
||||||
if (bgp_server_main_created)
|
if (bgp_server_main_created)
|
||||||
return 0;
|
return 0;
|
||||||
if (bgp_socket(bgp, bm->port, bm->address) < 0)
|
if (list_isempty(bm->addresses)) {
|
||||||
return BGP_ERR_INVALID_VALUE;
|
if (bgp_socket(bgp, bm->port, NULL) < 0)
|
||||||
|
return BGP_ERR_INVALID_VALUE;
|
||||||
|
} else {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
|
||||||
|
if (bgp_socket(bgp, bm->port, address) < 0)
|
||||||
|
return BGP_ERR_INVALID_VALUE;
|
||||||
|
}
|
||||||
bgp_server_main_created = 1;
|
bgp_server_main_created = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3288,7 +3296,8 @@ struct bgp *bgp_get_evpn(void)
|
|||||||
int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
|
int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
|
||||||
bool create)
|
bool create)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
struct listnode *node;
|
||||||
|
char *address;
|
||||||
|
|
||||||
/* Create BGP server socket, if listen mode not disabled */
|
/* Create BGP server socket, if listen mode not disabled */
|
||||||
if (!bgp || bgp_option_check(BGP_OPT_NO_LISTEN))
|
if (!bgp || bgp_option_check(BGP_OPT_NO_LISTEN))
|
||||||
@ -3317,9 +3326,14 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
|
|||||||
*/
|
*/
|
||||||
if (vrf->vrf_id == VRF_UNKNOWN)
|
if (vrf->vrf_id == VRF_UNKNOWN)
|
||||||
return 0;
|
return 0;
|
||||||
ret = bgp_socket(bgp, bm->port, bm->address);
|
if (list_isempty(bm->addresses)) {
|
||||||
if (ret < 0)
|
if (bgp_socket(bgp, bm->port, NULL) < 0)
|
||||||
return BGP_ERR_INVALID_VALUE;
|
return BGP_ERR_INVALID_VALUE;
|
||||||
|
} else {
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
|
||||||
|
if (bgp_socket(bgp, bm->port, address) < 0)
|
||||||
|
return BGP_ERR_INVALID_VALUE;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return bgp_check_main_socket(create, bgp);
|
return bgp_check_main_socket(create, bgp);
|
||||||
@ -7445,7 +7459,8 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgp_master_init(struct thread_master *master, const int buffer_size)
|
void bgp_master_init(struct thread_master *master, const int buffer_size,
|
||||||
|
struct list *addresses)
|
||||||
{
|
{
|
||||||
qobj_init();
|
qobj_init();
|
||||||
|
|
||||||
@ -7455,6 +7470,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
|
|||||||
bm->bgp = list_new();
|
bm->bgp = list_new();
|
||||||
bm->listen_sockets = list_new();
|
bm->listen_sockets = list_new();
|
||||||
bm->port = BGP_PORT_DEFAULT;
|
bm->port = BGP_PORT_DEFAULT;
|
||||||
|
bm->addresses = addresses;
|
||||||
bm->master = master;
|
bm->master = master;
|
||||||
bm->start_time = bgp_clock();
|
bm->start_time = bgp_clock();
|
||||||
bm->t_rmap_update = NULL;
|
bm->t_rmap_update = NULL;
|
||||||
|
@ -125,8 +125,8 @@ struct bgp_master {
|
|||||||
/* BGP port number. */
|
/* BGP port number. */
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
|
||||||
/* Listener address */
|
/* Listener addresses */
|
||||||
char *address;
|
struct list *addresses;
|
||||||
|
|
||||||
/* The Mac table */
|
/* The Mac table */
|
||||||
struct hash *self_mac_hash;
|
struct hash *self_mac_hash;
|
||||||
@ -1872,8 +1872,8 @@ extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
|
|||||||
|
|
||||||
extern int bgp_config_write(struct vty *);
|
extern int bgp_config_write(struct vty *);
|
||||||
|
|
||||||
extern void bgp_master_init(struct thread_master *master,
|
extern void bgp_master_init(struct thread_master *master, const int buffer_size,
|
||||||
const int buffer_size);
|
struct list *addresses);
|
||||||
|
|
||||||
extern void bgp_init(unsigned short instance);
|
extern void bgp_init(unsigned short instance);
|
||||||
extern void bgp_pthreads_run(void);
|
extern void bgp_pthreads_run(void);
|
||||||
|
@ -31,12 +31,23 @@ be specified (:ref:`common-invocation-options`).
|
|||||||
|
|
||||||
.. option:: -l, --listenon
|
.. option:: -l, --listenon
|
||||||
|
|
||||||
Specify a specific IP address for bgpd to listen on, rather than its default
|
Specify specific IP addresses for bgpd to listen on, rather than its default
|
||||||
of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal
|
of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal
|
||||||
address, or to run multiple bgpd processes on one host.
|
address, or to run multiple bgpd processes on one host. Multiple addresses
|
||||||
|
can be specified.
|
||||||
|
|
||||||
|
In the following example, bgpd is started listening for connections on the
|
||||||
|
addresses 100.0.1.2 and fd00::2:2. The options -d (runs in daemon mode) and
|
||||||
|
-f (uses specific configuration file) are also used in this example as we
|
||||||
|
are likely to run multiple bgpd instances, each one with different
|
||||||
|
configurations, when using -l option.
|
||||||
|
|
||||||
Note that this option implies the --no_kernel option, and no learned routes will be installed into the linux kernel.
|
Note that this option implies the --no_kernel option, and no learned routes will be installed into the linux kernel.
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
# /usr/lib/frr/bgpd -d -f /some-folder/bgpd.conf -l 100.0.1.2 -l fd00::2:2
|
||||||
|
|
||||||
.. option:: -n, --no_kernel
|
.. option:: -n, --no_kernel
|
||||||
|
|
||||||
Do not install learned routes into the linux kernel. This option is useful
|
Do not install learned routes into the linux kernel. This option is useful
|
||||||
|
@ -1265,7 +1265,8 @@ int main(void)
|
|||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
qobj_init();
|
qobj_init();
|
||||||
bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE);
|
bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE,
|
||||||
|
list_new());
|
||||||
master = bm->master;
|
master = bm->master;
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
bgp_attr_init();
|
bgp_attr_init();
|
||||||
|
@ -912,7 +912,7 @@ int main(void)
|
|||||||
|
|
||||||
qobj_init();
|
qobj_init();
|
||||||
master = thread_master_create(NULL);
|
master = thread_master_create(NULL);
|
||||||
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
|
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
|
||||||
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
|
|
||||||
|
@ -1086,7 +1086,7 @@ int main(void)
|
|||||||
cmd_init(0);
|
cmd_init(0);
|
||||||
bgp_vty_init();
|
bgp_vty_init();
|
||||||
master = thread_master_create("test mp attr");
|
master = thread_master_create("test mp attr");
|
||||||
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
|
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
|
||||||
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
bgp_attr_init();
|
bgp_attr_init();
|
||||||
|
@ -393,7 +393,7 @@ static int global_test_init(void)
|
|||||||
qobj_init();
|
qobj_init();
|
||||||
master = thread_master_create(NULL);
|
master = thread_master_create(NULL);
|
||||||
zclient = zclient_new(master, &zclient_options_default);
|
zclient = zclient_new(master, &zclient_options_default);
|
||||||
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
|
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
|
||||||
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ int main(int argc, char *argv[])
|
|||||||
qobj_init();
|
qobj_init();
|
||||||
bgp_attr_init();
|
bgp_attr_init();
|
||||||
master = thread_master_create(NULL);
|
master = thread_master_create(NULL);
|
||||||
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
|
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
|
||||||
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
|
|
||||||
|
@ -1399,7 +1399,7 @@ static void bgp_startup(void)
|
|||||||
master = thread_master_create(NULL);
|
master = thread_master_create(NULL);
|
||||||
yang_init(true);
|
yang_init(true);
|
||||||
nb_init(master, bgpd_yang_modules, array_size(bgpd_yang_modules), false);
|
nb_init(master, bgpd_yang_modules, array_size(bgpd_yang_modules), false);
|
||||||
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
|
bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
|
||||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||||
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
vrf_init(NULL, NULL, NULL, NULL, NULL);
|
||||||
frr_pthread_init();
|
frr_pthread_init();
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
{
|
||||||
|
"ipv4base": "10.0.0.0",
|
||||||
|
"ipv4mask": 24,
|
||||||
|
"ipv6base": "fd00::",
|
||||||
|
"ipv6mask": 64,
|
||||||
|
"link_ip_start": {
|
||||||
|
"ipv4": "10.0.0.0",
|
||||||
|
"v4mask": 24,
|
||||||
|
"ipv6": "fd00::",
|
||||||
|
"v6mask": 64
|
||||||
|
},
|
||||||
|
"lo_prefix": {
|
||||||
|
"ipv4": "1.0.",
|
||||||
|
"v4mask": 32,
|
||||||
|
"ipv6": "2001:DB8:F::",
|
||||||
|
"v6mask": 128
|
||||||
|
},
|
||||||
|
"routers": {
|
||||||
|
"r1": {
|
||||||
|
"links": {
|
||||||
|
"lo": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto",
|
||||||
|
"type": "loopback"
|
||||||
|
},
|
||||||
|
"r2": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bgp": {
|
||||||
|
"local_as": "1000",
|
||||||
|
"address_family": {
|
||||||
|
"ipv4": {
|
||||||
|
"unicast": {
|
||||||
|
"neighbor": {
|
||||||
|
"r2": {
|
||||||
|
"dest_link": {
|
||||||
|
"r1": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"r2": {
|
||||||
|
"links": {
|
||||||
|
"lo": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto",
|
||||||
|
"type": "loopback"
|
||||||
|
},
|
||||||
|
"r1": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto"
|
||||||
|
},
|
||||||
|
"r3": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bgp": {
|
||||||
|
"local_as": "2000",
|
||||||
|
"address_family": {
|
||||||
|
"ipv4": {
|
||||||
|
"unicast": {
|
||||||
|
"neighbor": {
|
||||||
|
"r1": {
|
||||||
|
"dest_link": {
|
||||||
|
"r2": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"r3": {
|
||||||
|
"dest_link": {
|
||||||
|
"r2": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"r3": {
|
||||||
|
"links": {
|
||||||
|
"lo": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto",
|
||||||
|
"type": "loopback"
|
||||||
|
},
|
||||||
|
"r2": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto"
|
||||||
|
},
|
||||||
|
"r4": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bgp": {
|
||||||
|
"local_as": "2000",
|
||||||
|
"address_family": {
|
||||||
|
"ipv4": {
|
||||||
|
"unicast": {
|
||||||
|
"neighbor": {
|
||||||
|
"r2": {
|
||||||
|
"dest_link": {
|
||||||
|
"r3": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"r4": {
|
||||||
|
"dest_link": {
|
||||||
|
"r3": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"r4": {
|
||||||
|
"links": {
|
||||||
|
"lo": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto",
|
||||||
|
"type": "loopback"
|
||||||
|
},
|
||||||
|
"r3": {
|
||||||
|
"ipv4": "auto",
|
||||||
|
"ipv6": "auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bgp": {
|
||||||
|
"local_as": "3000",
|
||||||
|
"address_family": {
|
||||||
|
"ipv4": {
|
||||||
|
"unicast": {
|
||||||
|
"neighbor": {
|
||||||
|
"r3": {
|
||||||
|
"dest_link": {
|
||||||
|
"r4": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#
|
||||||
|
# test_bgp_listen_on_multiple_addresses.py
|
||||||
|
# Part of NetDEF Topology Tests
|
||||||
|
#
|
||||||
|
# Copyright (c) 2021 by Boeing Defence Australia
|
||||||
|
# Adriano Marto Reis
|
||||||
|
#
|
||||||
|
# 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_bgp_listen_on_multiple_addresses.py: Test BGP daemon listening for
|
||||||
|
connections on multiple addresses.
|
||||||
|
|
||||||
|
+------+ +------+ +------+ +------+
|
||||||
|
| | | | | | | |
|
||||||
|
| r1 |--------| r2 |--------| r3 |--------| r4 |
|
||||||
|
| | | | | | | |
|
||||||
|
+------+ +------+ +------+ +------+
|
||||||
|
|
||||||
|
| | | |
|
||||||
|
| AS 1000 | AS 2000 | AS 3000 |
|
||||||
|
| | | |
|
||||||
|
+------------+--------------------------------+-------------+
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
# Save the Current Working Directory to find configuration files.
|
||||||
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(os.path.join(CWD, "../"))
|
||||||
|
|
||||||
|
from lib.topogen import Topogen, get_topogen
|
||||||
|
from lib.topojson import build_topo_from_json, build_config_from_json
|
||||||
|
from lib.common_config import start_topology
|
||||||
|
from lib.topotest import router_json_cmp, run_and_expect
|
||||||
|
from mininet.topo import Topo
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
|
||||||
|
LISTEN_ADDRESSES = {
|
||||||
|
"r1": ["10.0.0.1"],
|
||||||
|
"r2": ["10.0.0.2", "10.0.1.1"],
|
||||||
|
"r3": ["10.0.1.2", "10.0.2.1"],
|
||||||
|
"r4": ["10.0.2.2"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Reads data from JSON File for topology and configuration creation.
|
||||||
|
jsonFile = "{}/bgp_listen_on_multiple_addresses.json".format(CWD)
|
||||||
|
try:
|
||||||
|
with open(jsonFile, "r") as topoJson:
|
||||||
|
topo = json.load(topoJson)
|
||||||
|
except IOError:
|
||||||
|
assert False, "Could not read file {}".format(jsonFile)
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateTopo(Topo):
|
||||||
|
"Topology builder."
|
||||||
|
|
||||||
|
def build(self, *_args, **_opts):
|
||||||
|
"Defines the allocation and relationship between routers and switches."
|
||||||
|
tgen = get_topogen(self)
|
||||||
|
build_topo_from_json(tgen, topo)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(mod):
|
||||||
|
"Sets up the test environment."
|
||||||
|
tgen = Topogen(TemplateTopo, mod.__name__)
|
||||||
|
|
||||||
|
# Adds extra parameters to bgpd so they listen for connections on specific
|
||||||
|
# multiple addresses.
|
||||||
|
for router_name in tgen.routers().keys():
|
||||||
|
tgen.net[router_name].daemons_options["bgpd"] = "-l " + " -l ".join(
|
||||||
|
LISTEN_ADDRESSES[router_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
start_topology(tgen)
|
||||||
|
build_config_from_json(tgen, topo)
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module(_mod):
|
||||||
|
"Tears-down the test environment."
|
||||||
|
tgen = get_topogen()
|
||||||
|
tgen.stop_topology()
|
||||||
|
|
||||||
|
|
||||||
|
def test_peering():
|
||||||
|
"Checks if the routers peer-up."
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
_bgp_converge_initial("r1", "10.0.0.2")
|
||||||
|
_bgp_converge_initial("r2", "10.0.0.1")
|
||||||
|
_bgp_converge_initial("r2", "10.0.1.2")
|
||||||
|
_bgp_converge_initial("r3", "10.0.1.1")
|
||||||
|
_bgp_converge_initial("r3", "10.0.2.2")
|
||||||
|
_bgp_converge_initial("r4", "10.0.2.1")
|
||||||
|
|
||||||
|
|
||||||
|
def test_listening_address():
|
||||||
|
"""
|
||||||
|
Checks if bgpd is only listening on the specified IP addresses.
|
||||||
|
"""
|
||||||
|
tgen = get_topogen()
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
for router in tgen.routers().values():
|
||||||
|
# bgpd must not be listening on the default address.
|
||||||
|
output = router.run("netstat -nlt4 | grep 0.0.0.0:179")
|
||||||
|
assert output == "", "{}: bpgd is listening on 0.0.0.0:179".format(router.name)
|
||||||
|
|
||||||
|
# bgpd must be listening on the specified addresses.
|
||||||
|
for address in LISTEN_ADDRESSES[router.name]:
|
||||||
|
output = router.run("netstat -nlt4 | grep {}:179".format(address))
|
||||||
|
assert output != "", "{}: bpgd is not listening on {}:179".format(
|
||||||
|
router.name, address
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _bgp_converge_initial(router_name, peer_address, timeout=180):
|
||||||
|
"""
|
||||||
|
Waits for the BGP connection between a given router and a given peer
|
||||||
|
(specified by its IP address) to be established. If the connection is
|
||||||
|
not established within a given timeout, then an exception is raised.
|
||||||
|
"""
|
||||||
|
tgen = get_topogen()
|
||||||
|
router = tgen.routers()[router_name]
|
||||||
|
expected = {"ipv4Unicast": {"peers": {peer_address: {"state": "Established"}}}}
|
||||||
|
|
||||||
|
test_func = partial(router_json_cmp, router, "show ip bgp summary json", expected)
|
||||||
|
_, result = run_and_expect(test_func, None, count=timeout, wait=1)
|
||||||
|
assert result is None, "{}: Failed to establish connection with {}".format(
|
||||||
|
router_name, peer_address
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user