summaryrefslogtreecommitdiff
path: root/lib/zclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zclient.c')
-rw-r--r--lib/zclient.c391
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;
}
}