diff options
| -rw-r--r-- | bgpd/bgp_main.c | 2 | ||||
| -rw-r--r-- | bgpd/bgp_network.c | 28 | ||||
| -rw-r--r-- | bgpd/bgp_network.h | 1 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 111 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 3 |
5 files changed, 132 insertions, 13 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index b5448b694e..717fe09762 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -261,6 +261,7 @@ static int bgp_vrf_enable(struct vrf *vrf) /* We have instance configured, link to VRF and make it "up". */ bgp_vrf_link(bgp, vrf); + bgp_handle_socket(bgp, vrf, old_vrf_id, true); /* Update any redistribute vrf bitmaps if the vrf_id changed */ if (old_vrf_id != bgp->vrf_id) bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); @@ -284,6 +285,7 @@ static int bgp_vrf_disable(struct vrf *vrf) bgp = bgp_lookup_by_name(vrf->name); if (bgp) { old_vrf_id = bgp->vrf_id; + bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false); /* We have instance configured, unlink from VRF and make it * "down". */ bgp_vrf_unlink(bgp, vrf); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index e3cca63905..59c59f924e 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -781,6 +781,32 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address) return 0; } +/* this function closes vrf socket + * this should be called only for vrf socket with netns backend + */ +void bgp_close_vrf_socket(struct bgp *bgp) +{ + struct listnode *node, *next; + struct bgp_listener *listener; + + if (!bgp) + return; + + if (bm->listen_sockets == NULL) + return; + + for (ALL_LIST_ELEMENTS(bm->listen_sockets, node, next, listener)) { + if (listener->bgp == bgp) { + thread_cancel(listener->thread); + close(listener->fd); + listnode_delete(bm->listen_sockets, listener); + XFREE(MTYPE_BGP_LISTENER, listener); + } + } +} + +/* this function closes main socket + */ void bgp_close(void) { struct listnode *node, *next; @@ -790,6 +816,8 @@ void bgp_close(void) return; for (ALL_LIST_ELEMENTS(bm->listen_sockets, node, next, listener)) { + if (listener->bgp) + continue; thread_cancel(listener->thread); close(listener->fd); listnode_delete(bm->listen_sockets, listener); diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 5691b73e22..f18484e000 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -25,6 +25,7 @@ extern int bgp_socket(struct bgp *bgp, unsigned short port, const char *address); +extern void bgp_close_vrf_socket(struct bgp *bgp); extern void bgp_close(void); extern int bgp_connect(struct peer *); extern int bgp_getsockname(struct peer *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 1d44eb76cd..07b9df31f2 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -101,6 +101,42 @@ static void bgp_if_finish(struct bgp *bgp); extern struct zclient *zclient; +/* handle main socket creation or deletion */ +static int bgp_check_main_socket(bool create, struct bgp *bgp) +{ + static int bgp_server_main_created; + struct listnode *bgpnode, *nbgpnode; + struct bgp *bgp_temp; + + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) + return 0; + if (create == true) { + if (bgp_server_main_created) + return 0; + if (bgp_socket(bgp, bm->port, bm->address) < 0) + return BGP_ERR_INVALID_VALUE; + bgp_server_main_created = 1; + return 0; + } + if (!bgp_server_main_created) + return 0; + /* only delete socket on some cases */ + for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp_temp)) { + /* do not count with current bgp */ + if (bgp_temp == bgp) + continue; + /* if other instance non VRF, do not delete socket */ + if (bgp_temp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + return 0; + /* vrf lite, do not delete socket */ + if (!vrf_is_mapped_on_netns(bgp_temp->vrf_id)) + return 0; + } + bgp_close(); + bgp_server_main_created = 0; + return 0; +} + void bgp_session_reset(struct peer *peer) { if (peer->doppelganger && (peer->doppelganger->status != Deleted) @@ -2981,11 +3017,67 @@ struct bgp *bgp_lookup_by_vrf_id(vrf_id_t vrf_id) return (vrf->info) ? (struct bgp *)vrf->info : NULL; } +/* handle socket creation or deletion, if necessary + * this is called for all new BGP instances + */ +int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, + vrf_id_t old_vrf_id, bool create) +{ + int ret = 0; + + /* Create BGP server socket, if listen mode not disabled */ + if (!bgp || bgp_option_check(BGP_OPT_NO_LISTEN)) + return 0; + if (bgp->name + && bgp->inst_type == BGP_INSTANCE_TYPE_VRF + && vrf) { + /* + * suppress vrf socket + */ + if (create == FALSE) { + if (vrf_is_mapped_on_netns(vrf->vrf_id)) + bgp_close_vrf_socket(bgp); + else + ret = bgp_check_main_socket(create, bgp); + return ret; + } + /* do nothing + * if vrf_id did not change + */ + if (vrf->vrf_id == old_vrf_id) + return 0; + if (old_vrf_id != VRF_UNKNOWN) { + /* look for old socket. close it. */ + bgp_close_vrf_socket(bgp); + } + /* if backend is not yet identified ( VRF_UNKNOWN) then + * creation will be done later + */ + if (vrf->vrf_id == VRF_UNKNOWN) + return 0; + /* if BGP VRF instance requested + * if backend is NETNS, create BGP server socket in the NETNS + */ + if (vrf_is_mapped_on_netns(bgp->vrf_id)) { + ret = bgp_socket(bgp, bm->port, bm->address); + if (ret < 0) + return BGP_ERR_INVALID_VALUE; + return 0; + } + } + /* if BGP VRF instance requested or VRF lite backend + * if BGP non VRF instance, create it + * if not already done + */ + return bgp_check_main_socket(create, bgp); +} + /* Called from VTY commands. */ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, enum bgp_instance_type inst_type) { struct bgp *bgp; + struct vrf *vrf = NULL; /* Multiple instance check. */ if (bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) { @@ -3033,25 +3125,19 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, bgp->t_rmap_def_originate_eval = NULL; - /* Create BGP server socket, if first instance. */ - if (list_isempty(bm->bgp) && !bgp_option_check(BGP_OPT_NO_LISTEN)) { - if (bgp_socket(bgp, bm->port, bm->address) < 0) - return BGP_ERR_INVALID_VALUE; - } - - listnode_add(bm->bgp, bgp); - /* If Default instance or VRF, link to the VRF structure, if present. */ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT || bgp->inst_type == BGP_INSTANCE_TYPE_VRF) { - struct vrf *vrf; - vrf = bgp_vrf_lookup_by_instance_type(bgp); if (vrf) bgp_vrf_link(bgp, vrf); } + /* BGP server socket already processed if BGP instance + * already part of the list + */ + bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, true); + listnode_add(bm->bgp, bgp); - /* Register with Zebra, if needed */ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) bgp_zebra_instance_register(bgp); @@ -3188,8 +3274,6 @@ int bgp_delete(struct bgp *bgp) * routes to be processed still referencing the struct bgp. */ listnode_delete(bm->bgp, bgp); - if (list_isempty(bm->bgp)) - bgp_close(); /* Deregister from Zebra, if needed */ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) @@ -3199,6 +3283,7 @@ int bgp_delete(struct bgp *bgp) bgp_if_finish(bgp); vrf = bgp_vrf_lookup_by_instance_type(bgp); + bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false); if (vrf) bgp_vrf_unlink(bgp, vrf); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 91a9f11620..7f55b753ab 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1355,6 +1355,9 @@ extern void bgp_instance_up(struct bgp *); extern void bgp_instance_down(struct bgp *); extern int bgp_delete(struct bgp *); +extern int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, + vrf_id_t old_vrf_id, bool create); + extern int bgp_flag_set(struct bgp *, int); extern int bgp_flag_unset(struct bgp *, int); extern int bgp_flag_check(struct bgp *, int); |
