]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #1959 from donaldsharp/route_map_doc
authorLou Berger <lberger@labn.net>
Fri, 30 Mar 2018 12:10:06 +0000 (08:10 -0400)
committerGitHub <noreply@github.com>
Fri, 30 Mar 2018 12:10:06 +0000 (08:10 -0400)
Route map doc

16 files changed:
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
lib/log.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
zebra/label_manager.c
zebra/label_manager.h
zebra/subdir.am
zebra/table_manager.c [new file with mode: 0644]
zebra/table_manager.h [new file with mode: 0644]
zebra/zebra_fpm_protobuf.c
zebra/zebra_ns.c
zebra/zebra_vrf.c
zebra/zserv.c

index 77416e3cfd47b080f0ff9cbf4995513e5606116f..269dcc7cb67b00d5c7384173584518d0e517f59e 100644 (file)
@@ -970,6 +970,64 @@ static int bgp_table_map_apply(struct route_map *map, struct prefix *p,
        return 0;
 }
 
+static struct thread *bgp_tm_thread_connect;
+static bool bgp_tm_status_connected;
+
+static int bgp_zebra_tm_connect(struct thread *t)
+{
+       struct zclient *zclient;
+       int delay = 10, ret = 0;
+
+       zclient = THREAD_ARG(t);
+       if (bgp_tm_status_connected && zclient->sock > 0)
+               delay = 60;
+       else {
+               bgp_tm_status_connected = false;
+               ret = tm_table_manager_connect(zclient);
+       }
+       if (ret < 0) {
+               zlog_warn("Error connecting to table manager!");
+               bgp_tm_status_connected = false;
+       } else {
+               if (!bgp_tm_status_connected)
+                       zlog_debug("Connecting to table manager. Success");
+               bgp_tm_status_connected = true;
+       }
+       thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
+                        &bgp_tm_thread_connect);
+       return 0;
+}
+
+void bgp_zebra_init_tm_connect(void)
+{
+       int delay = 1;
+
+       /* if already set, do nothing
+        */
+       if (bgp_tm_thread_connect != NULL)
+               return;
+       bgp_tm_status_connected = false;
+       thread_add_timer(bm->master, bgp_zebra_tm_connect, zclient, delay,
+                        &bgp_tm_thread_connect);
+}
+
+int bgp_zebra_get_table_range(uint32_t chunk_size,
+                             uint32_t *start, uint32_t *end)
+{
+       int ret;
+
+       if (!bgp_tm_status_connected)
+               return -1;
+       ret = tm_get_table_chunk(zclient, chunk_size, start, end);
+       if (ret < 0) {
+               zlog_err("BGP: Error getting table chunk %u", chunk_size);
+               return -1;
+       }
+       zlog_info("BGP: Table Manager returns range from chunk %u is [%u %u]",
+                chunk_size, *start, *end);
+       return 0;
+}
+
 void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                        struct bgp_info *info, struct bgp *bgp, afi_t afi,
                        safi_t safi)
index 68c495cf8b3fed67f79987509e966ef07549bfc6..7263317b6f5a07aa3941447ef6d407b80258118d 100644 (file)
 #include "vxlan.h"
 
 extern void bgp_zebra_init(struct thread_master *master);
+extern void bgp_zebra_init_tm_connect(void);
 extern void bgp_zebra_destroy(void);
+extern int bgp_zebra_get_table_range(uint32_t chunk_size,
+                                    uint32_t *start, uint32_t *end);
 extern int bgp_if_update_all(void);
 extern void bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t,
                                      safi_t);
index 515d90e04934fe4e6066cc9d5aeddd9a334fd3a1..97f0ffcf2c54706f2a2ffb755b371dd2319030ee 100644 (file)
@@ -1973,6 +1973,10 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
                bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
        }
 
+       if (safi == SAFI_FLOWSPEC) {
+               /* connect to table manager */
+               bgp_zebra_init_tm_connect();
+       }
        return ret;
 }
 
index 35298f1fa3f706328b0e4d4000444bd8aae57985..f5aff756dde5e2587986c87afa35e3ff5052cb97 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -965,6 +965,9 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_RULE_ADD),
        DESC_ENTRY(ZEBRA_RULE_DELETE),
        DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER),
+       DESC_ENTRY(ZEBRA_TABLE_MANAGER_CONNECT),
+       DESC_ENTRY(ZEBRA_GET_TABLE_CHUNK),
+       DESC_ENTRY(ZEBRA_RELEASE_TABLE_CHUNK),
 };
 #undef DESC_ENTRY
 
index 4659bce1b17082b44ae17ce066b524eb9a0e095d..7308beaaf25619ff0cca0acd8c528073a71fd1bc 100644 (file)
@@ -2123,6 +2123,168 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
        return 0;
 }
 
+/**
+ * Connect to table manager in a syncronous way
+ *
+ * It first writes the request to zcient output buffer and then
+ * immediately reads the answer from the input buffer.
+ *
+ * @param zclient Zclient used to connect to table manager (zebra)
+ * @result Result of response
+ */
+int tm_table_manager_connect(struct zclient *zclient)
+{
+       int ret;
+       struct stream *s;
+       uint8_t result;
+
+       if (zclient_debug)
+               zlog_debug("Connecting to Table Manager");
+
+       if (zclient->sock < 0)
+               return -1;
+
+       /* send request */
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, VRF_DEFAULT);
+
+       /* proto */
+       stream_putc(s, zclient->redist_default);
+       /* instance */
+       stream_putw(s, zclient->instance);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       ret = zclient_send_message(zclient);
+       if (ret < 0)
+               return -1;
+
+       if (zclient_debug)
+               zlog_debug("%s: Table manager connect request sent",
+                          __func__);
+
+       /* read response */
+       if (zclient_read_sync_response(zclient, ZEBRA_TABLE_MANAGER_CONNECT)
+           != 0)
+               return -1;
+
+       /* result */
+       s = zclient->ibuf;
+       STREAM_GETC(s, result);
+       if (zclient_debug)
+               zlog_debug(
+                       "%s: Table Manager connect response received, result %u",
+                       __func__, result);
+
+       return (int)result;
+stream_failure:
+       return 0;
+}
+
+/**
+ * Function to request a table chunk in a syncronous way
+ *
+ * It first writes the request to zclient output buffer and then
+ * immediately reads the answer from the input buffer.
+ *
+ * @param zclient Zclient used to connect to table manager (zebra)
+ * @param chunk_size Amount of table requested
+ * @param start to write first assigned chunk table RT ID to
+ * @param end To write last assigned chunk table RT ID to
+ * @result 0 on success, -1 otherwise
+ */
+int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
+                      uint32_t *start, uint32_t *end)
+{
+       int ret;
+       struct stream *s;
+
+       if (zclient_debug)
+               zlog_debug("Getting Table Chunk");
+
+       if (zclient->sock < 0)
+               return -1;
+
+       /* send request */
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, VRF_DEFAULT);
+       /* chunk size */
+       stream_putl(s, chunk_size);
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       ret = writen(zclient->sock, s->data, stream_get_endp(s));
+       if (ret < 0) {
+               zlog_err("%s: can't write to zclient->sock", __func__);
+               close(zclient->sock);
+               zclient->sock = -1;
+               return -1;
+       }
+       if (ret == 0) {
+               zlog_err("%s: zclient->sock connection closed", __func__);
+               close(zclient->sock);
+               zclient->sock = -1;
+               return -1;
+       }
+       if (zclient_debug)
+               zlog_debug("%s: Table chunk request (%d bytes) sent", __func__,
+                          ret);
+
+       /* read response */
+       if (zclient_read_sync_response(zclient, ZEBRA_GET_TABLE_CHUNK) != 0)
+               return -1;
+
+       s = zclient->ibuf;
+       /* start and end table IDs */
+       STREAM_GETL(s, *start);
+       STREAM_GETL(s, *end);
+
+       if (zclient_debug)
+               zlog_debug("Table Chunk assign: %u - %u ", *start, *end);
+
+stream_failure:
+       return 0;
+}
+
+/**
+ * Function to release a table chunk
+ *
+ * @param zclient Zclient used to connect to table manager (zebra)
+ * @param start First label of table
+ * @param end Last label of chunk
+ * @result 0 on success, -1 otherwise
+ */
+int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
+                          uint32_t end)
+{
+       struct stream *s;
+
+       if (zclient_debug)
+               zlog_debug("Releasing Table Chunk");
+
+       if (zclient->sock < 0)
+               return -1;
+
+       /* send request */
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s, ZEBRA_RELEASE_TABLE_CHUNK, VRF_DEFAULT);
+
+       /* start */
+       stream_putl(s, start);
+       /* end */
+       stream_putl(s, end);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
+
 int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
 {
        struct stream *s;
index b51c5184632e8cc203d99abfa5bee6c79df1ad04..04f2a5c17868bc5873f0e374c6146b93e1e65e39 100644 (file)
@@ -132,6 +132,9 @@ typedef enum {
        ZEBRA_RULE_ADD,
        ZEBRA_RULE_DELETE,
        ZEBRA_RULE_NOTIFY_OWNER,
+       ZEBRA_TABLE_MANAGER_CONNECT,
+       ZEBRA_GET_TABLE_CHUNK,
+       ZEBRA_RELEASE_TABLE_CHUNK,
 } zebra_message_types_t;
 
 struct redist_proto {
@@ -538,6 +541,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
                              uint32_t *end);
 extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
                                  uint32_t end);
+extern int tm_table_manager_connect(struct zclient *zclient);
+extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
+                             uint32_t *start, uint32_t *end);
+extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
+                                 uint32_t end);
+
 extern int zebra_send_pw(struct zclient *zclient, int command,
                         struct zapi_pw *pw);
 extern void zebra_read_pw_status_update(int command, struct zclient *zclient,
index ec530397be8cdd3ce4b422960ef9c76f19642dac..3887602231a4a1252e25588f2914ec29c732d655 100644 (file)
@@ -433,7 +433,8 @@ typedef enum {
        SAFI_ENCAP = 4,
        SAFI_EVPN = 5,
        SAFI_LABELED_UNICAST = 6,
-       SAFI_MAX = 7
+       SAFI_FLOWSPEC = 7,
+       SAFI_MAX = 8
 } safi_t;
 
 /*
index ad881b819cff180b06cf06a41fe12bcb9c6cbc0d..38869e80ecfdbd0c829ec7c49a2bc646f85015ce 100644 (file)
@@ -363,7 +363,7 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
  * @param instance Instance, to identify the owner
  * @return Number of chunks released
  */
-int release_daemon_chunks(uint8_t proto, unsigned short instance)
+int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
 {
        struct listnode *node;
        struct label_manager_chunk *lmc;
index a26e195b71e180064e0b804fdbebf3505c2dd1f2..4395e6897e7efdbc4d61407971db2523cf6c68c0 100644 (file)
@@ -69,7 +69,7 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
                                               uint8_t keep, uint32_t size);
 int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
                        uint32_t end);
-int release_daemon_chunks(uint8_t proto, unsigned short instance);
+int release_daemon_label_chunks(uint8_t proto, unsigned short instance);
 void label_manager_close(void);
 
 #endif /* _LABEL_MANAGER_H */
index ef157b7539e84787df7f7fe4bd378ff7d4940d4e..9dbff7d40c1bec66654525918938f6bc27d002d2 100644 (file)
@@ -70,6 +70,7 @@ zebra_zebra_SOURCES = \
        zebra/zserv.c \
        zebra/zebra_netns_id.c \
        zebra/zebra_netns_notify.c \
+       zebra/table_manager.c \
        # end
 
 zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS)
@@ -113,6 +114,7 @@ noinst_HEADERS += \
        zebra/zserv.h \
        zebra/zebra_netns_id.h \
        zebra/zebra_netns_notify.h \
+       zebra/table_manager.h \
        # end
 
 zebra_zebra_irdp_la_SOURCES = \
diff --git a/zebra/table_manager.c b/zebra/table_manager.c
new file mode 100644 (file)
index 0000000..db07f40
--- /dev/null
@@ -0,0 +1,235 @@
+/* zebra table Manager for routing table identifier management
+ * Copyright (C) 2018 6WIND
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "zebra.h"
+#include "zserv.h"
+#include "lib/log.h"
+#include "lib/memory.h"
+#include "lib/table.h"
+#include "lib/network.h"
+#include "lib/stream.h"
+#include "lib/zclient.h"
+#include "lib/libfrr.h"
+#include "lib/vrf.h"
+
+#include "zebra_vrf.h"
+#include "label_manager.h" /* for NO_PROTO */
+#include "table_manager.h"
+
+/* routing table identifiers
+ *
+ */
+#ifdef SUNOS_5
+/* SunOS
+ */
+#else
+#if !defined(GNU_LINUX) && !defined(SUNOS_5)
+/* BSD systems
+ */
+#else
+/* Linux Systems
+ */
+#define RT_TABLE_ID_LOCAL                  255
+#define RT_TABLE_ID_MAIN                   254
+#define RT_TABLE_ID_DEFAULT                253
+#define RT_TABLE_ID_COMPAT                 252
+#define RT_TABLE_ID_UNSPEC                 0
+#endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
+#endif /* SUNOS_5 */
+#define RT_TABLE_ID_UNRESERVED_MIN         1
+#define RT_TABLE_ID_UNRESERVED_MAX         0xffffffff
+
+struct table_manager tbl_mgr;
+
+DEFINE_MGROUP(TABLE_MGR, "Table Manager");
+DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
+
+static void delete_table_chunk(void *val)
+{
+       XFREE(MTYPE_TM_CHUNK, val);
+}
+
+/**
+ * Init table manager
+ */
+void table_manager_enable(ns_id_t ns_id)
+{
+       if (ns_id != NS_DEFAULT)
+               return;
+       tbl_mgr.lc_list = list_new();
+       tbl_mgr.lc_list->del = delete_table_chunk;
+}
+
+/**
+ * Core function, assigns table chunks
+ *
+ * It first searches through the list to check if there's one available
+ * (previously released). Otherwise it creates and assigns a new one
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @para size Size of the table chunk
+ * @return Pointer to the assigned table chunk
+ */
+struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
+                                              uint32_t size)
+{
+       struct table_manager_chunk *tmc;
+       struct listnode *node;
+       uint32_t start;
+
+       /* first check if there's one available */
+       for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+               if (tmc->proto == NO_PROTO
+                   && tmc->end - tmc->start + 1 == size) {
+                       tmc->proto = proto;
+                       tmc->instance = instance;
+                       return tmc;
+               }
+       }
+       /* otherwise create a new one */
+       tmc = XCALLOC(MTYPE_TM_CHUNK, sizeof(struct table_manager_chunk));
+       if (!tmc)
+               return NULL;
+
+       /* table RT IDs range are [1;252] and [256;0xffffffff]
+        * - check if the requested range can be within the first range,
+        * otherwise elect second one
+        * - TODO : vrf-lites have their own table identifier.
+        * In that case, table_id should be removed from the table range.
+        */
+       if (list_isempty(tbl_mgr.lc_list))
+               start = RT_TABLE_ID_UNRESERVED_MIN;
+       else
+               start = ((struct table_manager_chunk *)listgetdata(
+                          listtail(tbl_mgr.lc_list)))->end + 1;
+
+#ifdef SUNOS_5
+/* SunOS
+ */
+#else
+#if !defined(GNU_LINUX) && !defined(SUNOS_5)
+/* BSD systems
+ */
+#else
+/* Linux Systems
+ */
+       /* if not enough room space between MIN and COMPAT,
+        * then begin after LOCAL
+        */
+       if (start < RT_TABLE_ID_COMPAT && (size >
+                               RT_TABLE_ID_COMPAT
+                               - RT_TABLE_ID_UNRESERVED_MIN))
+               start = RT_TABLE_ID_LOCAL + 1;
+#endif /* !def(GNU_LINUX) && !defined(SUNOS_5) */
+#endif /* SUNOS_5 */
+       tmc->start = start;
+       if (RT_TABLE_ID_UNRESERVED_MAX - size  + 1 < start) {
+               zlog_err("Reached max table id. Start/Size %u/%u",
+                        start, size);
+               XFREE(MTYPE_TM_CHUNK, tmc);
+               return NULL;
+       }
+       tmc->end = tmc->start + size - 1;
+       tmc->proto = proto;
+       tmc->instance = instance;
+       listnode_add(tbl_mgr.lc_list, tmc);
+
+       return tmc;
+}
+
+/**
+ * Core function, release no longer used table chunks
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @param start First table RT ID of the chunk
+ * @param end Last table RT ID of the chunk
+ * @return 0 on success, -1 otherwise
+ */
+int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
+                       uint32_t end)
+{
+       struct listnode *node;
+       struct table_manager_chunk *tmc;
+       int ret = -1;
+
+       /* check that size matches */
+       zlog_debug("Releasing table chunk: %u - %u", start, end);
+       /* find chunk and disown */
+       for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+               if (tmc->start != start)
+                       continue;
+               if (tmc->end != end)
+                       continue;
+               if (tmc->proto != proto || tmc->instance != instance) {
+                       zlog_err("%s: Daemon mismatch!!", __func__);
+                       continue;
+               }
+               tmc->proto = NO_PROTO;
+               tmc->instance = 0;
+               ret = 0;
+               break;
+       }
+       if (ret != 0)
+               zlog_err("%s: Table chunk not released!!", __func__);
+
+       return ret;
+}
+
+/**
+ * Release table chunks from a client.
+ *
+ * Called on client disconnection or reconnection. It only releases chunks
+ * with empty keep value.
+ *
+ * @param proto Daemon protocol of client, to identify the owner
+ * @param instance Instance, to identify the owner
+ * @return Number of chunks released
+ */
+int release_daemon_table_chunks(uint8_t proto, uint16_t instance)
+{
+       struct listnode *node;
+       struct table_manager_chunk *tmc;
+       int count = 0;
+       int ret;
+
+       for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+               if (tmc->proto == proto && tmc->instance == instance) {
+                       ret = release_table_chunk(tmc->proto, tmc->instance,
+                                                 tmc->start, tmc->end);
+                       if (ret == 0)
+                               count++;
+               }
+       }
+
+       zlog_debug("%s: Released %d table chunks", __func__, count);
+
+       return count;
+}
+
+void table_manager_disable(ns_id_t ns_id)
+{
+       if (ns_id != NS_DEFAULT)
+               return;
+       list_delete_and_null(&tbl_mgr.lc_list);
+}
diff --git a/zebra/table_manager.h b/zebra/table_manager.h
new file mode 100644 (file)
index 0000000..527d5c2
--- /dev/null
@@ -0,0 +1,63 @@
+/* zebra table Manager for routing table identifier management
+ * Copyright (C) 2018 6WIND
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _TABLE_MANAGER_H
+#define _TABLE_MANAGER_H
+
+#include <stdint.h>
+
+#include "lib/linklist.h"
+#include "lib/thread.h"
+
+/*
+ * Table chunk struct
+ * Client daemon which the chunk belongs to can be identified by either
+ * proto (daemon protocol) + instance + VRF.
+ * If the client then passes a non-empty value to keep field when it requests
+ * for chunks, the chunks won't be garbage collected and the client will be
+ * responsible of its release.
+ * Otherwise, if the keep field is not set (value 0) for the chunk, it will be
+ * automatically released when the client disconnects or when it reconnects
+ * (in case it died unexpectedly, we can know it's the same because it will have
+ * the same proto and instance values)
+ */
+struct table_manager_chunk {
+       vrf_id_t vrf_id;
+       uint8_t proto;
+       uint16_t instance;
+       uint32_t start; /* First table RT ID of the chunk */
+       uint32_t end;   /* Last table RT ID of the chunk */
+};
+
+/*
+ * Main table manager struct
+ * Holds a linked list of table chunks.
+ */
+struct table_manager {
+       struct list *lc_list;
+};
+
+void table_manager_enable(ns_id_t ns_id);
+struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
+                                              uint32_t size);
+int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
+                       uint32_t end);
+int release_daemon_table_chunks(uint8_t proto, uint16_t instance);
+void table_manager_disable(ns_id_t ns_id);
+
+#endif /* _TABLE_MANAGER_H */
index e661b6efc77748065d9b17c1b73b2e364475c813..ebd632270c7d004b855799e55fcd3c2776a3dcd7 100644 (file)
@@ -163,6 +163,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator,
        msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST;
        msg->key = fpm_route_key_create(allocator, rib_dest_prefix(dest));
        qpb_protocol_set(&msg->protocol, re->type);
+       msg->has_route_type = 1;
        msg->route_type = FPM__ROUTE_TYPE__NORMAL;
        msg->metric = re->metric;
 
@@ -245,6 +246,7 @@ static Fpm__Message *create_route_message(qpb_allocator_t *allocator,
        fpm__message__init(msg);
 
        if (!re) {
+               msg->has_type = 1;
                msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE;
                msg->delete_route =
                        create_delete_route_message(allocator, dest, re);
@@ -255,6 +257,7 @@ static Fpm__Message *create_route_message(qpb_allocator_t *allocator,
                return msg;
        }
 
+       msg->has_type = 1;
        msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE;
        msg->add_route = create_add_route_message(allocator, dest, re);
        if (!msg->add_route) {
index 66b1131e3983641908a61915dc14bebd88b4ca6d..7393f767afa3d20b72c67670c5b40e84cca94e32 100644 (file)
@@ -38,6 +38,7 @@
 #include "zebra_netns_id.h"
 #include "zebra_pbr.h"
 #include "rib.h"
+#include "table_manager.h"
 
 extern struct zebra_privs_t zserv_privs;
 
@@ -147,6 +148,9 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
        interface_list(zns);
        route_read(zns);
 
+       /* Initiate Table Manager per ZNS */
+       table_manager_enable(ns_id);
+
        return 0;
 }
 
@@ -259,6 +263,8 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
 
        kernel_terminate(zns);
 
+       table_manager_disable(zns->ns_id);
+
        zns->ns_id = NS_DEFAULT;
 
        return 0;
index dfb02f15a9647b98c1dcd10bbc5ecd49c037b774..fe1b100575ba3df5d5d1c8ef33589e653838a518 100644 (file)
@@ -122,8 +122,8 @@ static int zebra_vrf_enable(struct vrf *vrf)
        /* Inform clients that the VRF is now active. This is an
         * add for the clients.
         */
-       zebra_vrf_add_update(zvrf);
 
+       zebra_vrf_add_update(zvrf);
        /* Allocate tables */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
index 538487a9cde7537de83e29f48938a83c3adf1804..645deac277bed6d7c9ae520600105de425ff5617 100644 (file)
@@ -61,6 +61,7 @@
 #include "zebra/zebra_vxlan.h"
 #include "zebra/rt.h"
 #include "zebra/zebra_pbr.h"
+#include "zebra/table_manager.h"
 
 /* Event list of zebra. */
 enum event { ZEBRA_READ, ZEBRA_WRITE };
@@ -2186,6 +2187,60 @@ stream_failure:
        return;
 }
 
+static int zsend_table_manager_connect_response(struct zserv *client,
+                                               vrf_id_t vrf_id, uint16_t result)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, vrf_id);
+
+       /* result */
+       stream_putc(s, result);
+
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zebra_server_send_message(client, s);
+}
+
+/* Send response to a table manager connect request to client */
+static void zread_table_manager_connect(struct zserv *client,
+                                       struct stream *msg,
+                                       vrf_id_t vrf_id)
+{
+       struct stream *s;
+       uint8_t proto;
+       uint16_t instance;
+
+       s = msg;
+
+       /* Get data. */
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
+
+       /* accept only dynamic routing protocols */
+       if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) {
+               zlog_err("client %d has wrong protocol %s", client->sock,
+                        zebra_route_string(proto));
+               zsend_table_manager_connect_response(client, vrf_id, 1);
+               return;
+       }
+       zlog_notice("client %d with vrf %u instance %u connected as %s",
+                   client->sock, vrf_id, instance, zebra_route_string(proto));
+       client->proto = proto;
+       client->instance = instance;
+
+       /*
+        * Release previous labels of same protocol and instance.
+        * This is done in case it restarted from an unexpected shutdown.
+        */
+       release_daemon_table_chunks(proto, instance);
+
+       zsend_table_manager_connect_response(client, vrf_id, 0);
+
+ stream_failure:
+       return;
+}
+
 static void zread_label_manager_connect(struct zserv *client,
                                        struct stream *msg, vrf_id_t vrf_id)
 {
@@ -2217,7 +2272,7 @@ static void zread_label_manager_connect(struct zserv *client,
          Release previous labels of same protocol and instance.
          This is done in case it restarted from an unexpected shutdown.
        */
-       release_daemon_chunks(proto, instance);
+       release_daemon_label_chunks(proto, instance);
 
        zlog_debug(
                " Label Manager client connected: sock %d, proto %s, vrf %u instance %u",
@@ -2225,7 +2280,7 @@ static void zread_label_manager_connect(struct zserv *client,
        /* send response back */
        zsend_label_manager_connect_response(client, vrf_id, 0);
 
-stream_failure:
+ stream_failure:
        return;
 }
 
@@ -2305,6 +2360,92 @@ static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
        }
 }
 
+/* Send response to a get table chunk request to client */
+static int zsend_assign_table_chunk_response(struct zserv *client,
+                                            vrf_id_t vrf_id,
+                                            struct table_manager_chunk *tmc)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, vrf_id);
+
+       if (tmc) {
+               /* start and end labels */
+               stream_putl(s, tmc->start);
+               stream_putl(s, tmc->end);
+       }
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zebra_server_send_message(client, s);
+}
+
+static void zread_get_table_chunk(struct zserv *client, struct stream *msg,
+                                 vrf_id_t vrf_id)
+{
+       struct stream *s;
+       uint32_t size;
+       struct table_manager_chunk *tmc;
+
+       /* Get input stream.  */
+       s = msg;
+
+       /* Get data. */
+       STREAM_GETL(s, size);
+
+       tmc = assign_table_chunk(client->proto, client->instance, size);
+       if (!tmc)
+               zlog_err("%s: Unable to assign Table Chunk of size %u",
+                        __func__, size);
+       else
+               zlog_debug("Assigned Table Chunk %u - %u", tmc->start,
+                          tmc->end);
+       /* send response back */
+       zsend_assign_table_chunk_response(client, vrf_id, tmc);
+
+stream_failure:
+       return;
+}
+
+static void zread_release_table_chunk(struct zserv *client, struct stream *msg)
+{
+       struct stream *s;
+       uint32_t start, end;
+
+       /* Get input stream.  */
+       s = msg;
+
+       /* Get data. */
+       STREAM_GETL(s, start);
+       STREAM_GETL(s, end);
+
+       release_table_chunk(client->proto, client->instance, start, end);
+
+stream_failure:
+       return;
+}
+
+static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
+{
+       /* to avoid sending other messages like ZERBA_INTERFACE_UP */
+       if (hdr->command == ZEBRA_TABLE_MANAGER_CONNECT)
+               zread_table_manager_connect(client, msg, zvrf_id(zvrf));
+       else {
+               /* Sanity: don't allow 'unidentified' requests */
+               if (!client->proto) {
+                       zlog_err(
+                                "Got table request from an unidentified client");
+                       return;
+               }
+               if (hdr->command == ZEBRA_GET_TABLE_CHUNK)
+                       zread_get_table_chunk(client, msg,
+                                             zvrf_id(zvrf));
+               else if (hdr->command == ZEBRA_RELEASE_TABLE_CHUNK)
+                       zread_release_table_chunk(client, msg);
+       }
+}
+
 static void zread_pseudowire(ZAPI_HANDLER_ARGS)
 {
        struct stream *s;
@@ -2627,6 +2768,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_PW_UNSET] = zread_pseudowire,
        [ZEBRA_RULE_ADD] = zread_rule,
        [ZEBRA_RULE_DELETE] = zread_rule,
+       [ZEBRA_TABLE_MANAGER_CONNECT] = zread_table_manager_request,
+       [ZEBRA_GET_TABLE_CHUNK] = zread_table_manager_request,
+       [ZEBRA_RELEASE_TABLE_CHUNK] = zread_table_manager_request,
 };
 
 static inline void zserv_handle_commands(struct zserv *client,
@@ -2658,7 +2802,10 @@ static void zebra_client_free(struct zserv *client)
        zebra_client_close_cleanup_rnh(client);
 
        /* Release Label Manager chunks */
-       release_daemon_chunks(client->proto, client->instance);
+       release_daemon_label_chunks(client->proto, client->instance);
+
+       /* Release Table Manager chunks */
+       release_daemon_table_chunks(client->proto, client->instance);
 
        /* Cleanup any FECs registered by this client. */
        zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),