From f2867068e679900582aeb263d1723f8d7c3aa0ed Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 23 Feb 2020 11:27:15 +0000 Subject: [PATCH] lib: add new structures for srv6-locator (step2) This commit is a part of #5853 works that add new structures for SRv6-locator. This structure will be used by zebra and another routing daemon and its ZAPI messaging to manage SRv6-locator. Encoder/decoder for ZAPI stream is also added by this commit. Real configuration mechanism isn't implemented at this commit. later commit add real configure implementation. This commit add only SRv6-locator's structures and misc functions. Signed-off-by: Hiroki Shirokura --- lib/srv6.c | 85 +++++++++++++++++++++++ lib/srv6.h | 32 +++++++++ lib/zclient.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/zclient.h | 16 +++++ 4 files changed, 317 insertions(+) diff --git a/lib/srv6.c b/lib/srv6.c index 9b9f402987..d59d2d75b0 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -22,6 +22,10 @@ #include "srv6.h" #include "log.h" +DEFINE_QOBJ_TYPE(srv6_locator); +DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); +DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); + const char *seg6local_action2str(uint32_t action) { switch (action) { @@ -117,3 +121,84 @@ const char *seg6local_context2str(char *str, size_t size, return str; } } + +struct srv6_locator *srv6_locator_alloc(const char *name) +{ + struct srv6_locator *locator = NULL; + + locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator)); + strlcpy(locator->name, name, sizeof(locator->name)); + locator->chunks = list_new(); + QOBJ_REG(locator, srv6_locator); + return locator; +} + +struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) +{ + struct srv6_locator_chunk *chunk = NULL; + + chunk = XCALLOC(MTYPE_SRV6_LOCATOR_CHUNK, + sizeof(struct srv6_locator_chunk)); + return chunk; +} + +void srv6_locator_free(struct srv6_locator *locator) +{ + XFREE(MTYPE_SRV6_LOCATOR, locator); +} + +void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk) +{ + XFREE(MTYPE_SRV6_LOCATOR_CHUNK, chunk); +} + +json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) +{ + char str[256]; + json_object *jo_root = NULL; + + jo_root = json_object_new_object(); + prefix2str(&chunk->prefix, str, sizeof(str)); + json_object_string_add(jo_root, "prefix", str); + json_object_string_add(jo_root, "proto", + zebra_route_string(chunk->proto)); + + return jo_root; +} + +json_object *srv6_locator_json(const struct srv6_locator *loc) +{ + char str[256]; + struct listnode *node; + struct srv6_locator_chunk *chunk; + json_object *jo_root = NULL; + json_object *jo_chunk = NULL; + json_object *jo_chunks = NULL; + + jo_root = json_object_new_object(); + + /* set name */ + json_object_string_add(jo_root, "name", loc->name); + + /* set prefix */ + prefix2str(&loc->prefix, str, sizeof(str)); + json_object_string_add(jo_root, "prefix", str); + + /* set function_bits_length */ + json_object_int_add(jo_root, "function_bits_length", + loc->function_bits_length); + + /* set status_up */ + json_object_boolean_add(jo_root, "status_up", + loc->status_up); + + /* set chunks */ + jo_chunks = json_object_new_array(); + json_object_object_add(jo_root, "chunks", jo_chunks); + for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { + jo_chunk = srv6_locator_chunk_json(chunk); + json_object_array_add(jo_chunks, jo_chunk); + } + + return jo_root; +} diff --git a/lib/srv6.h b/lib/srv6.h index b72b098c78..46ff830e7f 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -21,10 +21,14 @@ #define _FRR_SRV6_H #include +#include "prefix.h" +#include "json.h" + #include #include #define SRV6_MAX_SIDS 16 +#define SRV6_LOCNAME_SIZE 256 #ifdef __cplusplus extern "C" { @@ -69,6 +73,27 @@ struct seg6local_context { uint32_t table; }; +struct srv6_locator { + char name[SRV6_LOCNAME_SIZE]; + struct prefix_ipv6 prefix; + uint8_t function_bits_length; + int algonum; + uint64_t current; + bool status_up; + struct list *chunks; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(srv6_locator); + +struct srv6_locator_chunk { + uint8_t keep; + uint8_t proto; + uint16_t instance; + uint32_t session_id; + struct prefix_ipv6 prefix; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -126,6 +151,13 @@ const char *seg6local_context2str(char *str, size_t size, int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); +extern struct srv6_locator *srv6_locator_alloc(const char *name); +extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); +extern void srv6_locator_free(struct srv6_locator *locator); +extern void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk); +json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); +json_object *srv6_locator_json(const struct srv6_locator *loc); + #ifdef __cplusplus } #endif diff --git a/lib/zclient.c b/lib/zclient.c index bf67392cbe..c8bb720591 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -41,6 +41,7 @@ #include "lib_errors.h" #include "srte.h" #include "printfrr.h" +#include "srv6.h" DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient"); DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs"); @@ -2637,6 +2638,174 @@ stream_failure: return -1; } +/** + * Connect to srv6 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 srv6 manager (zebra) + * @result Result of response + */ +int srv6_manager_connect(struct zclient *zclient) +{ + struct stream *s; + int ret, result = 0; + uint16_t cmd = ZEBRA_SRV6_MANAGER_CONNECT; + + if (zclient_debug) + zlog_debug("Connecting to SRv6 Manager"); + + if (zclient->sock < 0) { + zlog_debug("%s: invalid zclient socket", __func__); + return -1; + } + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, cmd, VRF_DEFAULT); + + stream_putc(s, zclient->redist_default); /* proto */ + stream_putw(s, zclient->instance); /* instance */ + stream_putw_at(s, 0, stream_get_endp(s)); + ret = writen(zclient->sock, s->data, stream_get_endp(s)); + if (ret < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "Can't write to zclient sock"); + close(zclient->sock); + zclient->sock = -1; + return -1; + } + if (ret == 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "Zclient sock closed"); + close(zclient->sock); + zclient->sock = -1; + return -1; + } + if (zclient_debug) + zlog_debug("SRv6 Manager connect request sent (%d bytes)", ret); + + /* read response */ + if (zclient_read_sync_response(zclient, cmd) + != 0) + return -1; + + s = zclient->ibuf; + + /* read instance and proto */ + uint8_t proto; + uint16_t instance; + + STREAM_GETC(s, proto); + STREAM_GETW(s, instance); + + /* sanity */ + if (proto != zclient->redist_default) + flog_err( + EC_LIB_ZAPI_ENCODE, + "Wrong proto (%u) in SRv6 Manager connect response. Should be %u", + proto, zclient->redist_default); + if (instance != zclient->instance) + flog_err( + EC_LIB_ZAPI_ENCODE, + "Wrong instId (%u) in SRv6 Manager connect response. Should be %u", + instance, zclient->instance); + + /* result code */ + STREAM_GETC(s, result); + if (zclient_debug) + zlog_debug("SRv6 Manager connect-response received, result %u", result); + + return (int)result; + +stream_failure: + return -1; +} + +/** + * Function to request a srv6-locator chunk in an Asyncronous 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 locator_name Name of SRv6-locator + * @result 0 on success, -1 otherwise + */ +int srv6_manager_get_locator_chunk(struct zclient *zclient, + const char *locator_name) +{ + struct stream *s; + const size_t len = strlen(locator_name); + + if (zclient_debug) + zlog_debug("Getting SRv6-Locator Chunk %s", locator_name); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, VRF_DEFAULT); + + /* proto */ + stream_putc(s, zclient->redist_default); + + /* instance */ + stream_putw(s, zclient->instance); + + /* locator_name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/** + * Function to release a srv6-locator chunk + * + * @param zclient Zclient used to connect to table manager (zebra) + * @param locator_name Name of SRv6-locator + * @result 0 on success, -1 otherwise + */ +int srv6_manager_release_locator_chunk(struct zclient *zclient, + const char *locator_name) +{ + struct stream *s; + const size_t len = strlen(locator_name); + + if (zclient_debug) + zlog_debug("Releasing SRv6-Locator Chunk %s", locator_name); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, + VRF_DEFAULT); + + /* proto */ + stream_putc(s, zclient->redist_default); + + /* instance */ + stream_putw(s, zclient->instance); + + /* locator_name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * @@ -3927,6 +4096,21 @@ static int zclient_read(struct thread *thread) case ZEBRA_MLAG_FORWARD_MSG: zclient_mlag_handle_msg(command, zclient, length, vrf_id); break; + case ZEBRA_SRV6_LOCATOR_ADD: + if (zclient->srv6_locator_add) + (*zclient->srv6_locator_add)(command, zclient, length, + vrf_id); + break; + case ZEBRA_SRV6_LOCATOR_DELETE: + if (zclient->srv6_locator_delete) + (*zclient->srv6_locator_delete)(command, zclient, + length, vrf_id); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK: + if (zclient->process_srv6_locator_chunk) + (*zclient->process_srv6_locator_chunk)(command, zclient, + length, vrf_id); + break; case ZEBRA_ERROR: zclient_handle_error(command, zclient, length, vrf_id); break; diff --git a/lib/zclient.h b/lib/zclient.h index 3f5225f097..6496e79c89 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -39,6 +39,7 @@ #include "mlag.h" #include "srte.h" +#include "srv6.h" #ifdef __cplusplus extern "C" { @@ -216,6 +217,11 @@ typedef enum { ZEBRA_NHG_NOTIFY_OWNER, ZEBRA_EVPN_REMOTE_NH_ADD, ZEBRA_EVPN_REMOTE_NH_DEL, + ZEBRA_SRV6_LOCATOR_ADD, + ZEBRA_SRV6_LOCATOR_DELETE, + ZEBRA_SRV6_MANAGER_CONNECT, + ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, + ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -387,6 +393,11 @@ struct zclient { int (*mlag_process_down)(void); int (*mlag_handle_msg)(struct stream *msg, int len); int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS); + int (*srv6_locator_add)(ZAPI_CALLBACK_ARGS); + int (*srv6_locator_delete)(ZAPI_CALLBACK_ARGS); + int (*srv6_function_add)(ZAPI_CALLBACK_ARGS); + int (*srv6_function_delete)(ZAPI_CALLBACK_ARGS); + void (*process_srv6_locator_chunk)(ZAPI_CALLBACK_ARGS); int (*handle_error)(enum zebra_error_types error); int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS); int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS); @@ -1051,6 +1062,11 @@ 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 srv6_manager_connect(struct zclient *zclient); +extern int srv6_manager_get_locator_chunk(struct zclient *zclient, + const char *locator_name); +extern int srv6_manager_release_locator_chunk(struct zclient *zclient, + const char *locator_name); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd,