]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: server socket is created for all enabled VRF
authorPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 26 Jan 2018 11:25:34 +0000 (12:25 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Feb 2018 10:11:24 +0000 (11:11 +0100)
Upon creation of BGP instances, server socket may or may not be created.
In the case of VRF instances, if the VRF backend relies on NETNS, then
a new server socket will be created for each BGP VRF instance. If the
VRF backend relies on VRF LITE, then only one server socket will be
enough. Moreover, At startup, with BGP VRF configuration, a server
socket may not be created if VRF is not the default one or VRF is not
recognized yet.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/bgp_main.c
bgpd/bgp_network.c
bgpd/bgp_network.h
bgpd/bgpd.c
bgpd/bgpd.h

index b5448b694e064c35af21820ed8d7d0686de16d60..717fe09762177d7311fd1abc913445a7b484aebb 100644 (file)
@@ -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);
index e3cca639055723054672dd68ed0f8fd2bb03bd3d..59c59f924eeb464d1d8ea608d62bb5c7d1b9b80a 100644 (file)
@@ -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);
index 5691b73e2225309f74ef9ed7edbf795f4d6072bb..f18484e0009721605032fc3c4606e8f5414cf7bd 100644 (file)
@@ -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 *);
index 1d44eb76cdbffbbd7b802ad0b07f4da2fd7f340f..07b9df31f220802a853c5ec7ea2c6e1923931d95 100644 (file)
@@ -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);
 
index 91a9f11620c76dd79a092142efc0d2b10aa8204f..7f55b753abbc5cec3a7865f29c7e2afa6b8e7310 100644 (file)
@@ -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);