diff options
Diffstat (limited to 'zebra/zserv.c')
-rw-r--r-- | zebra/zserv.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/zebra/zserv.c b/zebra/zserv.c index 064489acd..f9205a12c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -55,6 +55,7 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_fpm.h" #include "zebra/zebra_mroute.h" +#include "zebra/label_manager.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -113,6 +114,9 @@ zebra_server_send_message(struct zserv *client) if (client->t_suicide) return -1; + if (client->is_synchronous) + return 0; + stream_set_getp(client->obuf, 0); client->last_write_cmd = stream_getw_from(client->obuf, 6); switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), @@ -1770,6 +1774,167 @@ zread_mpls_labels (int command, struct zserv *client, u_short length, distance, out_label); } } +/* Send response to a label manager connect request to client */ +static int +zsend_label_manager_connect_response (struct zserv *client, vrf_id_t vrf_id, u_short result) +{ + struct stream *s; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); + + /* result */ + stream_putc (s, result); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (client->sock, s->data, stream_get_endp (s)); +} + +static void +zread_label_manager_connect (struct zserv *client, vrf_id_t vrf_id) +{ + struct stream *s; + /* type of protocol (lib/zebra.h) */ + u_char proto; + u_short instance; + + /* Get input stream. */ + s = client->ibuf; + + /* Get data. */ + proto = stream_getc (s); + instance = stream_getw (s); + + /* 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_label_manager_connect_response (client, vrf_id, 1); + return; + } + zlog_notice ("client %d with instance %u connected as %s", + client->sock, 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_chunks (proto, instance); + + zlog_debug (" Label Manager client connected: sock %d, proto %s, instance %u", + client->sock, zebra_route_string(proto), instance); + /* send response back */ + zsend_label_manager_connect_response (client, vrf_id, 0); +} +/* Send response to a get label chunk request to client */ +static int +zsend_assign_label_chunk_response (struct zserv *client, vrf_id_t vrf_id, + struct label_manager_chunk *lmc) +{ + struct stream *s; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, ZEBRA_GET_LABEL_CHUNK, vrf_id); + + if (lmc) + { + /* keep */ + stream_putc (s, lmc->keep); + /* start and end labels */ + stream_putl (s, lmc->start); + stream_putl (s, lmc->end); + + } + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + + return writen (client->sock, s->data, stream_get_endp (s)); +} + +static void +zread_get_label_chunk (struct zserv *client, vrf_id_t vrf_id) +{ + struct stream *s; + u_char keep; + uint32_t size; + struct label_manager_chunk *lmc; + + /* Get input stream. */ + s = client->ibuf; + + /* Get data. */ + keep = stream_getc (s); + size = stream_getl (s); + + lmc = assign_label_chunk (client->proto, client->instance, keep, size); + if (!lmc) + zlog_err ("%s: Unable to assign Label Chunk of size %u", __func__, size); + else + zlog_debug ("Assigned Label Chunk %u - %u to %u", + lmc->start, lmc->end, keep); + /* send response back */ + zsend_assign_label_chunk_response (client, vrf_id, lmc); +} + +static void +zread_release_label_chunk (struct zserv *client) +{ + struct stream *s; + uint32_t start, end; + + /* Get input stream. */ + s = client->ibuf; + + /* Get data. */ + start = stream_getl (s); + end = stream_getl (s); + + release_label_chunk (client->proto, client->instance, start, end); +} +static void +zread_label_manager_request (int cmd, struct zserv *client, vrf_id_t vrf_id) +{ + /* to avoid sending other messages like ZERBA_INTERFACE_UP */ + if (cmd == ZEBRA_LABEL_MANAGER_CONNECT) + client->is_synchronous = 1; + + /* external label manager */ + if (lm_is_external) + { + if (zread_relay_label_manager_request (cmd, client) != 0) + zsend_label_manager_connect_response (client, vrf_id, 1); + } + /* this is a label manager */ + else + { + if (cmd == ZEBRA_LABEL_MANAGER_CONNECT) + zread_label_manager_connect (client, vrf_id); + else + { + /* Sanity: don't allow 'unidentified' requests */ + if (!client->proto) + { + zlog_err ("Got label request from an unidentified client"); + return; + } + if (cmd == ZEBRA_GET_LABEL_CHUNK) + zread_get_label_chunk (client, vrf_id); + else if (cmd == ZEBRA_RELEASE_LABEL_CHUNK) + zread_release_label_chunk (client); + } + } +} /* Cleanup registered nexthops (across VRFs) upon client disconnect. */ static void @@ -1807,6 +1972,9 @@ zebra_client_close (struct zserv *client) /* Cleanup any registered nexthops - across all VRFs. */ zebra_client_close_cleanup_rnh (client); + /* Release Label Manager chunks */ + release_daemon_chunks (client->proto, client->instance); + /* Close file descriptor. */ if (client->sock) { @@ -1868,6 +2036,9 @@ zebra_client_create (int sock) client->ifinfo = vrf_bitmap_init (); client->ridinfo = vrf_bitmap_init (); + /* by default, it's not a synchronous client */ + client->is_synchronous = 0; + /* Add this client to linked list. */ listnode_add (zebrad.client_list, client); @@ -2087,6 +2258,11 @@ zebra_client_read (struct thread *thread) case ZEBRA_IPMR_ROUTE_STATS: zebra_ipmr_route_stats (client, sock, length, zvrf); break; + case ZEBRA_LABEL_MANAGER_CONNECT: + case ZEBRA_GET_LABEL_CHUNK: + case ZEBRA_RELEASE_LABEL_CHUNK: + zread_label_manager_request (command, client, vrf_id); + break; default: zlog_info ("Zebra received unknown command %d", command); break; |