diff options
Diffstat (limited to 'zebra/zserv.c')
| -rw-r--r-- | zebra/zserv.c | 334 |
1 files changed, 174 insertions, 160 deletions
diff --git a/zebra/zserv.c b/zebra/zserv.c index cbc9f2bed9..6295de0c2e 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -40,6 +40,7 @@ #include "nexthop.h" #include "vrf.h" #include "libfrr.h" +#include "sockopt.h" #include "zebra/zserv.h" #include "zebra/zebra_ns.h" @@ -693,7 +694,7 @@ static int zsend_write_nexthop(struct stream *s, struct nexthop *nexthop) } /* Nexthop register */ -static int zserv_rnh_register(struct zserv *client, int sock, u_short length, +static int zserv_rnh_register(struct zserv *client, u_short length, rnh_type_t type, struct zebra_vrf *zvrf) { struct rnh *rnh; @@ -754,7 +755,7 @@ static int zserv_rnh_register(struct zserv *client, int sock, u_short length, } /* Nexthop register */ -static int zserv_rnh_unregister(struct zserv *client, int sock, u_short length, +static int zserv_rnh_unregister(struct zserv *client, u_short length, rnh_type_t type, struct zebra_vrf *zvrf) { struct rnh *rnh; @@ -798,7 +799,7 @@ static int zserv_rnh_unregister(struct zserv *client, int sock, u_short length, #define ZEBRA_MIN_FEC_LENGTH 5 /* FEC register */ -static int zserv_fec_register(struct zserv *client, int sock, u_short length) +static int zserv_fec_register(struct zserv *client, u_short length) { struct stream *s; struct zebra_vrf *zvrf; @@ -849,7 +850,7 @@ static int zserv_fec_register(struct zserv *client, int sock, u_short length) } /* FEC unregister */ -static int zserv_fec_unregister(struct zserv *client, int sock, u_short length) +static int zserv_fec_unregister(struct zserv *client, u_short length) { struct stream *s; struct zebra_vrf *zvrf; @@ -1763,7 +1764,7 @@ static int zread_vrf_unregister(struct zserv *client, u_short length, } static void zread_mpls_labels(int command, struct zserv *client, u_short length, - vrf_id_t vrf_id) + struct zebra_vrf *zvrf) { struct stream *s; enum lsp_types_t type; @@ -1773,11 +1774,6 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, ifindex_t ifindex; mpls_label_t in_label, out_label; u_int8_t distance; - struct zebra_vrf *zvrf; - - zvrf = vrf_info_lookup(vrf_id); - if (!zvrf) - return; /* Get input stream. */ s = client->ibuf; @@ -1959,7 +1955,7 @@ static void zread_release_label_chunk(struct zserv *client) 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) + struct zebra_vrf *zvrf) { /* to avoid sending other messages like ZERBA_INTERFACE_UP */ if (cmd == ZEBRA_LABEL_MANAGER_CONNECT) @@ -1967,11 +1963,13 @@ static void zread_label_manager_request(int cmd, struct zserv *client, /* external label manager */ if (lm_is_external) - zread_relay_label_manager_request(cmd, client, vrf_id); + zread_relay_label_manager_request(cmd, client, + zvrf_id(zvrf)); /* this is a label manager */ else { if (cmd == ZEBRA_LABEL_MANAGER_CONNECT) - zread_label_manager_connect(client, vrf_id); + zread_label_manager_connect(client, + zvrf_id(zvrf)); else { /* Sanity: don't allow 'unidentified' requests */ if (!client->proto) { @@ -1980,7 +1978,8 @@ static void zread_label_manager_request(int cmd, struct zserv *client, return; } if (cmd == ZEBRA_GET_LABEL_CHUNK) - zread_get_label_chunk(client, vrf_id); + zread_get_label_chunk(client, + zvrf_id(zvrf)); else if (cmd == ZEBRA_RELEASE_LABEL_CHUNK) zread_release_label_chunk(client); } @@ -1988,10 +1987,9 @@ static void zread_label_manager_request(int cmd, struct zserv *client, } static int zread_pseudowire(int command, struct zserv *client, u_short length, - vrf_id_t vrf_id) + struct zebra_vrf *zvrf) { struct stream *s; - struct zebra_vrf *zvrf; char ifname[IF_NAMESIZE]; ifindex_t ifindex; int type; @@ -2004,10 +2002,6 @@ static int zread_pseudowire(int command, struct zserv *client, u_short length, uint8_t protocol; struct zebra_pw *pw; - zvrf = vrf_info_lookup(vrf_id); - if (!zvrf) - return -1; - /* Get input stream. */ s = client->ibuf; @@ -2210,7 +2204,7 @@ static void zebra_client_create(int sock) zebra_vrf_update_all(client); } -static int zread_interface_set_master(struct zserv *client, int sock, +static int zread_interface_set_master(struct zserv *client, u_short length) { struct interface *master; @@ -2235,122 +2229,11 @@ static int zread_interface_set_master(struct zserv *client, int sock, return 1; } -/* Handler of zebra service request. */ -static int zebra_client_read(struct thread *thread) +static inline void zserv_handle_commands(struct zserv *client, + uint16_t command, + uint16_t length, + struct zebra_vrf *zvrf) { - int sock; - struct zserv *client; - size_t already; - uint16_t length, command; - uint8_t marker, version; - vrf_id_t vrf_id; - struct zebra_vrf *zvrf; - - /* Get thread data. Reset reading thread because I'm running. */ - sock = THREAD_FD(thread); - client = THREAD_ARG(thread); - client->t_read = NULL; - - if (client->t_suicide) { - zebra_client_close(client); - return -1; - } - - /* Read length and command (if we don't have it already). */ - if ((already = stream_get_endp(client->ibuf)) < ZEBRA_HEADER_SIZE) { - ssize_t nbyte; - if (((nbyte = stream_read_try(client->ibuf, sock, - ZEBRA_HEADER_SIZE - already)) - == 0) - || (nbyte == -1)) { - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("connection closed socket [%d]", - sock); - zebra_client_close(client); - return -1; - } - if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { - /* Try again later. */ - zebra_event(ZEBRA_READ, sock, client); - return 0; - } - already = ZEBRA_HEADER_SIZE; - } - - /* Reset to read from the beginning of the incoming packet. */ - stream_set_getp(client->ibuf, 0); - - /* Fetch header values */ - length = stream_getw(client->ibuf); - marker = stream_getc(client->ibuf); - version = stream_getc(client->ibuf); - vrf_id = stream_getw(client->ibuf); - command = stream_getw(client->ibuf); - - if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { - zlog_err( - "%s: socket %d version mismatch, marker %d, version %d", - __func__, sock, marker, version); - zebra_client_close(client); - return -1; - } - if (length < ZEBRA_HEADER_SIZE) { - zlog_warn( - "%s: socket %d message length %u is less than header size %d", - __func__, sock, length, ZEBRA_HEADER_SIZE); - zebra_client_close(client); - return -1; - } - if (length > STREAM_SIZE(client->ibuf)) { - zlog_warn( - "%s: socket %d message length %u exceeds buffer size %lu", - __func__, sock, length, - (u_long)STREAM_SIZE(client->ibuf)); - zebra_client_close(client); - return -1; - } - - /* Read rest of data. */ - if (already < length) { - ssize_t nbyte; - if (((nbyte = stream_read_try(client->ibuf, sock, - length - already)) - == 0) - || (nbyte == -1)) { - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "connection closed [%d] when reading zebra data", - sock); - zebra_client_close(client); - return -1; - } - if (nbyte != (ssize_t)(length - already)) { - /* Try again later. */ - zebra_event(ZEBRA_READ, sock, client); - return 0; - } - } - - length -= ZEBRA_HEADER_SIZE; - - /* Debug packet information. */ - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("zebra message comes from socket [%d]", sock); - - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("zebra message received [%s] %d in VRF %u", - zserv_command_string(command), length, vrf_id); - - client->last_read_time = monotime(NULL); - client->last_read_cmd = command; - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - if (!zvrf) { - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) - zlog_debug("zebra received unknown VRF[%u]", vrf_id); - goto zclient_read_out; - } - switch (command) { case ZEBRA_ROUTER_ID_ADD: zread_router_id_add(client, length, zvrf); @@ -2405,101 +2288,227 @@ static int zebra_client_read(struct thread *thread) zread_hello(client); break; case ZEBRA_NEXTHOP_REGISTER: - zserv_rnh_register(client, sock, length, RNH_NEXTHOP_TYPE, + zserv_rnh_register(client, length, RNH_NEXTHOP_TYPE, zvrf); break; case ZEBRA_NEXTHOP_UNREGISTER: - zserv_rnh_unregister(client, sock, length, RNH_NEXTHOP_TYPE, + zserv_rnh_unregister(client, length, RNH_NEXTHOP_TYPE, zvrf); break; case ZEBRA_IMPORT_ROUTE_REGISTER: - zserv_rnh_register(client, sock, length, RNH_IMPORT_CHECK_TYPE, + zserv_rnh_register(client, length, RNH_IMPORT_CHECK_TYPE, zvrf); break; case ZEBRA_IMPORT_ROUTE_UNREGISTER: - zserv_rnh_unregister(client, sock, length, + zserv_rnh_unregister(client, length, RNH_IMPORT_CHECK_TYPE, zvrf); break; case ZEBRA_BFD_DEST_UPDATE: case ZEBRA_BFD_DEST_REGISTER: - zebra_ptm_bfd_dst_register(client, sock, length, command, zvrf); + zebra_ptm_bfd_dst_register(client, length, command, zvrf); break; case ZEBRA_BFD_DEST_DEREGISTER: - zebra_ptm_bfd_dst_deregister(client, sock, length, zvrf); + zebra_ptm_bfd_dst_deregister(client, length, zvrf); break; case ZEBRA_VRF_UNREGISTER: zread_vrf_unregister(client, length, zvrf); break; case ZEBRA_BFD_CLIENT_REGISTER: - zebra_ptm_bfd_client_register(client, sock, length); + zebra_ptm_bfd_client_register(client, length); break; case ZEBRA_INTERFACE_ENABLE_RADV: #if defined(HAVE_RTADV) - zebra_interface_radv_set(client, sock, length, zvrf, 1); + zebra_interface_radv_set(client, length, zvrf, 1); #endif break; case ZEBRA_INTERFACE_DISABLE_RADV: #if defined(HAVE_RTADV) - zebra_interface_radv_set(client, sock, length, zvrf, 0); + zebra_interface_radv_set(client, length, zvrf, 0); #endif break; case ZEBRA_MPLS_LABELS_ADD: case ZEBRA_MPLS_LABELS_DELETE: - zread_mpls_labels(command, client, length, vrf_id); + zread_mpls_labels(command, client, length, zvrf); break; case ZEBRA_IPMR_ROUTE_STATS: - zebra_ipmr_route_stats(client, sock, length, zvrf); + zebra_ipmr_route_stats(client, 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); + zread_label_manager_request(command, client, zvrf); break; case ZEBRA_FEC_REGISTER: - zserv_fec_register(client, sock, length); + zserv_fec_register(client, length); break; case ZEBRA_FEC_UNREGISTER: - zserv_fec_unregister(client, sock, length); + zserv_fec_unregister(client, length); break; case ZEBRA_ADVERTISE_DEFAULT_GW: - zebra_vxlan_advertise_gw_macip(client, sock, length, zvrf); + zebra_vxlan_advertise_gw_macip(client, length, zvrf); break; case ZEBRA_ADVERTISE_ALL_VNI: - zebra_vxlan_advertise_all_vni(client, sock, length, zvrf); + zebra_vxlan_advertise_all_vni(client, length, zvrf); break; case ZEBRA_REMOTE_VTEP_ADD: - zebra_vxlan_remote_vtep_add(client, sock, length, zvrf); + zebra_vxlan_remote_vtep_add(client, length, zvrf); break; case ZEBRA_REMOTE_VTEP_DEL: - zebra_vxlan_remote_vtep_del(client, sock, length, zvrf); + zebra_vxlan_remote_vtep_del(client, length, zvrf); break; case ZEBRA_REMOTE_MACIP_ADD: - zebra_vxlan_remote_macip_add(client, sock, length, zvrf); + zebra_vxlan_remote_macip_add(client, length, zvrf); break; case ZEBRA_REMOTE_MACIP_DEL: - zebra_vxlan_remote_macip_del(client, sock, length, zvrf); + zebra_vxlan_remote_macip_del(client, length, zvrf); break; case ZEBRA_INTERFACE_SET_MASTER: - zread_interface_set_master(client, sock, length); + zread_interface_set_master(client, length); break; case ZEBRA_PW_ADD: case ZEBRA_PW_DELETE: case ZEBRA_PW_SET: case ZEBRA_PW_UNSET: - zread_pseudowire(command, client, length, vrf_id); + zread_pseudowire(command, client, length, zvrf); break; default: zlog_info("Zebra received unknown command %d", command); break; } +} + +/* Handler of zebra service request. */ +static int zebra_client_read(struct thread *thread) +{ + int sock; + struct zserv *client; + size_t already; + uint16_t length, command; + uint8_t marker, version; + vrf_id_t vrf_id; + struct zebra_vrf *zvrf; + int packets = 10; + + /* Get thread data. Reset reading thread because I'm running. */ + sock = THREAD_FD(thread); + client = THREAD_ARG(thread); + client->t_read = NULL; if (client->t_suicide) { - /* No need to wait for thread callback, just kill immediately. - */ zebra_client_close(client); return -1; } + while (packets) { + /* Read length and command (if we don't have it already). */ + if ((already = stream_get_endp(client->ibuf)) + < ZEBRA_HEADER_SIZE) { + ssize_t nbyte; + if (((nbyte = + stream_read_try(client->ibuf, sock, + ZEBRA_HEADER_SIZE - already)) + == 0) + || (nbyte == -1)) { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("connection closed socket [%d]", + sock); + zebra_client_close(client); + return -1; + } + if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { + /* Try again later. */ + zebra_event(ZEBRA_READ, sock, client); + return 0; + } + already = ZEBRA_HEADER_SIZE; + } + + /* Reset to read from the beginning of the incoming packet. */ + stream_set_getp(client->ibuf, 0); + + /* Fetch header values */ + length = stream_getw(client->ibuf); + marker = stream_getc(client->ibuf); + version = stream_getc(client->ibuf); + vrf_id = stream_getw(client->ibuf); + command = stream_getw(client->ibuf); + + if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { + zlog_err( + "%s: socket %d version mismatch, marker %d, version %d", + __func__, sock, marker, version); + zebra_client_close(client); + return -1; + } + if (length < ZEBRA_HEADER_SIZE) { + zlog_warn( + "%s: socket %d message length %u is less than header size %d", + __func__, sock, length, ZEBRA_HEADER_SIZE); + zebra_client_close(client); + return -1; + } + if (length > STREAM_SIZE(client->ibuf)) { + zlog_warn( + "%s: socket %d message length %u exceeds buffer size %lu", + __func__, sock, length, + (u_long)STREAM_SIZE(client->ibuf)); + zebra_client_close(client); + return -1; + } + + /* Read rest of data. */ + if (already < length) { + ssize_t nbyte; + if (((nbyte = stream_read_try(client->ibuf, sock, + length - already)) + == 0) + || (nbyte == -1)) { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug( + "connection closed [%d] when reading zebra data", + sock); + zebra_client_close(client); + return -1; + } + if (nbyte != (ssize_t)(length - already)) { + /* Try again later. */ + zebra_event(ZEBRA_READ, sock, client); + return 0; + } + } + + length -= ZEBRA_HEADER_SIZE; + + /* Debug packet information. */ + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("zebra message comes from socket [%d]", sock); + + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("zebra message received [%s] %d in VRF %u", + zserv_command_string(command), length, vrf_id); + + client->last_read_time = monotime(NULL); + client->last_read_cmd = command; + + zvrf = zebra_vrf_lookup_by_id(vrf_id); + if (!zvrf) { + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + zlog_debug("zebra received unknown VRF[%u]", vrf_id); + goto zclient_read_out; + } + + zserv_handle_commands(client, command, length, zvrf); + + if (client->t_suicide) { + /* No need to wait for thread callback, just kill immediately. + */ + zebra_client_close(client); + return -1; + } + packets -= 1; + stream_reset(client->ibuf); + } + zclient_read_out: stream_reset(client->ibuf); zebra_event(ZEBRA_READ, sock, client); @@ -2573,6 +2582,11 @@ void zebra_zserv_socket_init(char *path) unlink(suna->sun_path); } + zserv_privs.change(ZPRIVS_RAISE); + setsockopt_so_recvbuf(sock, 1048576); + setsockopt_so_sendbuf(sock, 1048576); + zserv_privs.change(ZPRIVS_LOWER); + if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_RAISE)) zlog_err("Can't raise privileges"); |
