diff options
Diffstat (limited to 'lib/zclient.c')
| -rw-r--r-- | lib/zclient.c | 391 |
1 files changed, 356 insertions, 35 deletions
diff --git a/lib/zclient.c b/lib/zclient.c index 440de3635f..b3a9338928 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -14,10 +14,9 @@ * 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 GNU Zebra; see the file COPYING. If not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * 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 <zebra.h> @@ -26,6 +25,8 @@ #include "stream.h" #include "buffer.h" #include "network.h" +#include "vrf.h" +#include "vrf_int.h" #include "if.h" #include "log.h" #include "thread.h" @@ -33,8 +34,10 @@ #include "memory.h" #include "table.h" #include "nexthop.h" +#include "mpls.h" DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient") +DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs") /* Zebra client events. */ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; @@ -106,7 +109,7 @@ redist_add_instance (struct redist_proto *red, u_short instance) if (!red->instances) red->instances = list_new(); - in = calloc (1, sizeof(u_short)); + in = XMALLOC (MTYPE_REDIST_INST, sizeof(u_short)); *in = instance; listnode_add (red->instances, in); } @@ -121,7 +124,7 @@ redist_del_instance (struct redist_proto *red, u_short instance) return; listnode_delete(red->instances, id); - free (id); + XFREE (MTYPE_REDIST_INST, id); if (!red->instances->count) { red->enabled = 0; @@ -308,8 +311,9 @@ zclient_flush_data(struct thread *thread) return zclient_failed(zclient); break; case BUFFER_PENDING: - zclient->t_write = thread_add_write(zclient->master, zclient_flush_data, - zclient, zclient->sock); + zclient->t_write = NULL; + thread_add_write(zclient->master, zclient_flush_data, zclient, zclient->sock, + &zclient->t_write); break; case BUFFER_EMPTY: break; @@ -334,8 +338,8 @@ zclient_send_message(struct zclient *zclient) THREAD_OFF(zclient->t_write); break; case BUFFER_PENDING: - THREAD_WRITE_ON(zclient->master, zclient->t_write, - zclient_flush_data, zclient, zclient->sock); + thread_add_write(zclient->master, zclient_flush_data, zclient, + zclient->sock, &zclient->t_write); break; } return 0; @@ -731,6 +735,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, s = zclient->obuf; stream_reset (s); + /* Some checks for labeled-unicast. The current expectation is that each + * nexthop is accompanied by a label in the case of labeled-unicast. + */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) && + CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + /* We expect prefixes installed with labels and the number to match + * the number of nexthops. + */ + assert (api->label_num == api->nexthop_num); + } + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ @@ -747,7 +763,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) - { + { /* traditional 32-bit data units */ if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) { @@ -763,6 +779,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, { stream_putc (s, NEXTHOP_TYPE_IPV4); stream_put_in_addr (s, api->nexthop[i]); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL)) + stream_putl (s, api->label[i]); } for (i = 0; i < api->ifindex_num; i++) { @@ -786,7 +805,6 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, return zclient_send_message(zclient); } -#ifdef HAVE_IPV6 int zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, struct zapi_ipv6 *api) @@ -799,6 +817,18 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, s = zclient->obuf; stream_reset (s); + /* Some checks for labeled-unicast. The current expectation is that each + * nexthop is accompanied by a label in the case of labeled-unicast. + */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) && + CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + /* We expect prefixes installed with labels and the number to match + * the number of nexthops. + */ + assert (api->label_num == api->nexthop_num); + } + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ @@ -830,6 +860,9 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, { stream_putc (s, NEXTHOP_TYPE_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL)) + stream_putl (s, api->label[i]); } for (i = 0; i < api->ifindex_num; i++) { @@ -855,16 +888,31 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient, int zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, - struct zapi_ipv6 *api) + struct prefix_ipv6 *src_p, struct zapi_ipv6 *api) { int i; int psize; struct stream *s; + /* either we have !SRCPFX && src_p == NULL, or SRCPFX && src_p != NULL */ + assert (!(api->message & ZAPI_MESSAGE_SRCPFX) == !src_p); + /* Reset stream. */ s = zclient->obuf; stream_reset (s); + /* Some checks for labeled-unicast. The current expectation is that each + * nexthop is accompanied by a label in the case of labeled-unicast. + */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) && + CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + /* We expect prefixes installed with labels and the number to match + * the number of nexthops. + */ + assert (api->label_num == api->nexthop_num); + } + zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ @@ -879,6 +927,13 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, stream_putc (s, p->prefixlen); stream_write (s, (u_char *)&p->prefix, psize); + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_SRCPFX)) + { + psize = PSIZE (src_p->prefixlen); + stream_putc (s, src_p->prefixlen); + stream_write (s, (u_char *)&src_p->prefix, psize); + } + /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) { @@ -896,6 +951,9 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, { stream_putc (s, NEXTHOP_TYPE_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); + /* For labeled-unicast, each nexthop is followed by label. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL)) + stream_putl (s, api->label[i]); } for (i = 0; i < api->ifindex_num; i++) { @@ -918,7 +976,6 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, return zclient_send_message(zclient); } -#endif /* HAVE_IPV6 */ /* * send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE @@ -993,6 +1050,8 @@ zebra_router_id_update_read (struct stream *s, struct prefix *rid) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | metric | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | speed | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifmtu | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifmtu6 | @@ -1018,12 +1077,15 @@ zclient_vrf_add (struct zclient *zclient, vrf_id_t vrf_id) { struct vrf *vrf; char vrfname_tmp[VRF_NAMSIZ]; + struct vrf_data data; + stream_get (&data, zclient->ibuf, sizeof (struct vrf_data)); /* Read interface name. */ stream_get (vrfname_tmp, zclient->ibuf, VRF_NAMSIZ); /* Lookup/create vrf by vrf_id. */ vrf = vrf_get (vrf_id, vrfname_tmp); + vrf->data = data; vrf_enable (vrf); } @@ -1057,9 +1119,9 @@ zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id) stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* Lookup/create interface by name. */ - ifp = if_get_by_name_len_vrf (ifname_tmp, - strnlen (ifname_tmp, INTERFACE_NAMSIZ), - vrf_id, 0); + ifp = if_get_by_name_len (ifname_tmp, + strnlen (ifname_tmp, INTERFACE_NAMSIZ), + vrf_id, 0); zebra_interface_if_set_value (s, ifp); @@ -1083,9 +1145,9 @@ zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* Lookup this by interface index. */ - ifp = if_lookup_by_name_len_vrf (ifname_tmp, - strnlen (ifname_tmp, INTERFACE_NAMSIZ), - vrf_id); + ifp = if_lookup_by_name_len (ifname_tmp, + strnlen (ifname_tmp, INTERFACE_NAMSIZ), + vrf_id); if (ifp == NULL) { zlog_warn ("INTERFACE_STATE: Cannot find IF %s in VRF %d", @@ -1138,11 +1200,15 @@ struct interface * zebra_interface_link_params_read (struct stream *s) { struct if_link_params *iflp; - uint32_t ifindex = stream_getl (s); + ifindex_t ifindex; - struct interface *ifp = if_lookup_by_index (ifindex); + assert (s); + + ifindex = stream_getl (s); - if (ifp == NULL || s == NULL) + struct interface *ifp = if_lookup_by_index (ifindex, VRF_DEFAULT); + + if (ifp == NULL) { zlog_err ("%s: unknown ifindex %u, shouldn't happen", __func__, ifindex); @@ -1171,6 +1237,7 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->ptm_enable = stream_getc (s); ifp->ptm_status = stream_getc (s); ifp->metric = stream_getl (s); + ifp->speed = stream_getl (s); ifp->mtu = stream_getl (s); ifp->mtu6 = stream_getl (s); ifp->bandwidth = stream_getl (s); @@ -1289,7 +1356,7 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) ifindex = stream_getl (s); /* Lookup index. */ - ifp = if_lookup_by_index_vrf (ifindex, vrf_id); + ifp = if_lookup_by_index (ifindex, vrf_id); if (ifp == NULL) { zlog_warn ("INTERFACE_ADDRESS_%s: Cannot find IF %u in VRF %d", @@ -1383,7 +1450,7 @@ zebra_interface_nbr_address_read (int type, struct stream *s, vrf_id_t vrf_id) ifindex = stream_getl (s); /* Lookup index. */ - ifp = if_lookup_by_index_vrf (ifindex, vrf_id); + ifp = if_lookup_by_index (ifindex, vrf_id); if (ifp == NULL) { zlog_warn ("INTERFACE_NBR_%s: Cannot find IF %u in VRF %d", @@ -1434,7 +1501,7 @@ zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id, ifindex = stream_getl (s); /* Lookup interface. */ - ifp = if_lookup_by_index_vrf (ifindex, vrf_id); + ifp = if_lookup_by_index (ifindex, vrf_id); if (ifp == NULL) { zlog_warn ("INTERFACE_VRF_UPDATE: Cannot find IF %u in VRF %d", @@ -1449,6 +1516,255 @@ zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id, return ifp; } +/* filter unwanted messages until the expected one arrives */ +static int +zclient_read_sync_response (struct zclient *zclient, u_int16_t expected_cmd) +{ + struct stream *s; + u_int16_t size; + u_char marker; + u_char version; + vrf_id_t vrf_id; + u_int16_t cmd; + fd_set readfds; + int ret; + + ret = 0; + cmd = expected_cmd + 1; + while (ret == 0 && cmd != expected_cmd) + { + s = zclient->ibuf; + stream_reset (s); + + /* wait until response arrives */ + FD_ZERO (&readfds); + FD_SET (zclient->sock, &readfds); + select (zclient->sock+1, &readfds, NULL, NULL, NULL); + if (!FD_ISSET(zclient->sock, &readfds)) + continue; + /* read response */ + ret = zclient_read_header (s, zclient->sock, &size, &marker, &version, + &vrf_id, &cmd); + if (zclient_debug) + zlog_debug ("%s: Response (%d bytes) received", __func__, size); + } + if (ret != 0) + { + zlog_err ("%s: Invalid Sync Message Reply", __func__); + return -1; + } + + return 0; +} +/** + * Connect to label 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 label manager (zebra) + * @result Result of response + */ +int +lm_label_manager_connect (struct zclient *zclient) +{ + int ret; + struct stream *s; + u_char result; + + if (zclient_debug) + zlog_debug ("Connecting to Label Manager"); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset (s); + zclient_create_header (s, ZEBRA_LABEL_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 = 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: Label manager connect request (%d bytes) sent", __func__, ret); + + /* read response */ + if (zclient_read_sync_response (zclient, ZEBRA_LABEL_MANAGER_CONNECT) != 0) + return -1; + + /* result */ + s = zclient->ibuf; + result = stream_getc(s); + if (zclient_debug) + zlog_debug ("%s: Label Manager connect response received, result %u", + __func__, result); + + return (int)result; +} + +/** + * Function to request a label chunk in a syncronous way + * + * It first writes the request to zlcient output buffer and then + * immediately reads the answer from the input buffer. + * + * @param zclient Zclient used to connect to label manager (zebra) + * @param keep Avoid garbage collection + * @param chunk_size Amount of labels requested + * @param start To write first assigned chunk label to + * @param end To write last assigned chunk label to + * @result 0 on success, -1 otherwise + */ +int +lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, + uint32_t *start, uint32_t *end) +{ + int ret; + struct stream *s; + u_char response_keep; + + if (zclient_debug) + zlog_debug ("Getting Label Chunk"); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset (s); + zclient_create_header (s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT); + /* keep */ + stream_putc (s, keep); + /* 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: Label chunk request (%d bytes) sent", __func__, ret); + + /* read response */ + if (zclient_read_sync_response (zclient, ZEBRA_GET_LABEL_CHUNK) != 0) + return -1; + + s = zclient->ibuf; + /* keep */ + response_keep = stream_getc(s); + /* start and end labels */ + *start = stream_getl(s); + *end = stream_getl(s); + + /* not owning this response */ + if (keep != response_keep) + { + zlog_err ("%s: Invalid Label chunk: %u - %u, keeps mismatch %u != %u", + __func__, *start, *end, keep, response_keep); + } + /* sanity */ + if (*start > *end + || *start < MPLS_MIN_UNRESERVED_LABEL + || *end > MPLS_MAX_UNRESERVED_LABEL) + { + zlog_err ("%s: Invalid Label chunk: %u - %u", __func__, + *start, *end); + return -1; + } + + if (zclient_debug) + zlog_debug ("Label Chunk assign: %u - %u (%u) ", + *start, *end, response_keep); + + return 0; +} + +/** + * Function to release a label chunk + * + * @param zclient Zclient used to connect to label manager (zebra) + * @param start First label of chunk + * @param end Last label of chunk + * @result 0 on success, -1 otherwise + */ +int +lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end) +{ + int ret; + struct stream *s; + + if (zclient_debug) + zlog_debug ("Releasing Label Chunk"); + + if (zclient->sock < 0) + return -1; + + /* send request */ + s = zclient->obuf; + stream_reset (s); + zclient_create_header (s, ZEBRA_RELEASE_LABEL_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)); + + 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; + } + + return 0; +} + /* Zebra client message read function. */ static int zclient_read (struct thread *thread) @@ -1628,10 +1944,17 @@ zclient_read (struct thread *thread) case ZEBRA_REDISTRIBUTE_IPV6_DEL: if (zclient->redistribute_route_ipv6_del) (*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id); + break; case ZEBRA_INTERFACE_LINK_PARAMS: if (zclient->interface_link_params) (*zclient->interface_link_params) (command, zclient, length); break; + case ZEBRA_FEC_UPDATE: + if (zclient_debug) + zlog_debug("zclient rcvd fec update\n"); + if (zclient->fec_update) + (*zclient->fec_update) (command, zclient, length); + break; default: break; } @@ -1714,22 +2037,20 @@ zclient_event (enum event event, struct zclient *zclient) switch (event) { case ZCLIENT_SCHEDULE: - if (! zclient->t_connect) - zclient->t_connect = - thread_add_event (zclient->master, zclient_connect, zclient, 0); + thread_add_event(zclient->master, zclient_connect, zclient, 0, + &zclient->t_connect); break; case ZCLIENT_CONNECT: if (zclient_debug) zlog_debug ("zclient connect failures: %d schedule interval is now %d", zclient->fail, zclient->fail < 3 ? 10 : 60); - if (! zclient->t_connect) - zclient->t_connect = - thread_add_timer (zclient->master, zclient_connect, zclient, - zclient->fail < 3 ? 10 : 60); + thread_add_timer(zclient->master, zclient_connect, zclient, + zclient->fail < 3 ? 10 : 60, &zclient->t_connect); break; case ZCLIENT_READ: - zclient->t_read = - thread_add_read (zclient->master, zclient_read, zclient, zclient->sock); + zclient->t_read = NULL; + thread_add_read(zclient->master, zclient_read, zclient, zclient->sock, + &zclient->t_read); break; } } |
