summaryrefslogtreecommitdiff
path: root/zebra/zserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zserv.c')
-rw-r--r--zebra/zserv.c200
1 files changed, 172 insertions, 28 deletions
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 3477dc36d2..a59ef3031d 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -13,10 +13,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>
@@ -95,8 +94,9 @@ zserv_flush_data(struct thread *thread)
client = NULL;
break;
case BUFFER_PENDING:
- client->t_write = thread_add_write(zebrad.master, zserv_flush_data,
- client, client->sock);
+ client->t_write = NULL;
+ thread_add_write(zebrad.master, zserv_flush_data, client, client->sock,
+ &client->t_write);
break;
case BUFFER_EMPTY:
break;
@@ -128,15 +128,16 @@ zebra_server_send_message(struct zserv *client)
one do not check the return code. They do not allow for the
possibility that an I/O error may have caused the client to be
deleted. */
- client->t_suicide = thread_add_event(zebrad.master, zserv_delayed_close,
- client, 0);
+ client->t_suicide = NULL;
+ thread_add_event(zebrad.master, zserv_delayed_close, client, 0,
+ &client->t_suicide);
return -1;
case BUFFER_EMPTY:
THREAD_OFF(client->t_write);
break;
case BUFFER_PENDING:
- THREAD_WRITE_ON(zebrad.master, client->t_write,
- zserv_flush_data, client, client->sock);
+ thread_add_write(zebrad.master, zserv_flush_data, client, client->sock,
+ &client->t_write);
break;
}
@@ -934,6 +935,109 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
return 0;
}
+#define ZEBRA_MIN_FEC_LENGTH 5
+
+/* FEC register */
+static int
+zserv_fec_register (struct zserv *client, int sock, u_short length)
+{
+ struct stream *s;
+ struct zebra_vrf *zvrf;
+ u_short l = 0;
+ struct prefix p;
+ u_int16_t flags;
+ u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
+
+ s = client->ibuf;
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0; // unexpected
+
+ /*
+ * The minimum amount of data that can be sent for one fec
+ * registration
+ */
+ if (length < ZEBRA_MIN_FEC_LENGTH)
+ {
+ zlog_err ("fec_register: Received a fec register of length %d, it is of insufficient size to properly decode",
+ length);
+ return -1;
+ }
+
+ while (l < length)
+ {
+ flags = stream_getw(s);
+ p.family = stream_getw(s);
+ if (p.family != AF_INET &&
+ p.family != AF_INET6)
+ {
+ zlog_err ("fec_register: Received unknown family type %d\n",
+ p.family);
+ return -1;
+ }
+ p.prefixlen = stream_getc(s);
+ l += 5;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX)
+ {
+ label_index = stream_getl(s);
+ l += 4;
+ }
+ zebra_mpls_fec_register (zvrf, &p, label_index, client);
+ }
+
+ return 0;
+}
+
+/* FEC unregister */
+static int
+zserv_fec_unregister (struct zserv *client, int sock, u_short length)
+{
+ struct stream *s;
+ struct zebra_vrf *zvrf;
+ u_short l = 0;
+ struct prefix p;
+ //u_int16_t flags;
+
+ s = client->ibuf;
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0; // unexpected
+
+ /*
+ * The minimum amount of data that can be sent for one
+ * fec unregistration
+ */
+ if (length < ZEBRA_MIN_FEC_LENGTH)
+ {
+ zlog_err ("fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode",
+ length);
+ return -1;
+ }
+
+ while (l < length)
+ {
+ //flags = stream_getw(s);
+ (void)stream_getw(s);
+ p.family = stream_getw(s);
+ if (p.family != AF_INET &&
+ p.family != AF_INET6)
+ {
+ zlog_err ("fec_unregister: Received unknown family type %d\n",
+ p.family);
+ return -1;
+ }
+ p.prefixlen = stream_getc(s);
+ l += 5;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ zebra_mpls_fec_unregister (zvrf, &p, client);
+ }
+
+ return 0;
+}
+
/*
Modified version of zsend_ipv4_nexthop_lookup():
Query unicast rib if nexthop is not found on mrib.
@@ -1075,13 +1179,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
struct rib *rib;
struct prefix p;
u_char message;
- struct in_addr nexthop;
+ struct in_addr nhop_addr;
u_char nexthop_num;
u_char nexthop_type;
struct stream *s;
ifindex_t ifindex;
safi_t safi;
int ret;
+ mpls_label_t label;
+ struct nexthop *nexthop;
/* Get input stream. */
s = client->ibuf;
@@ -1123,13 +1229,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
rib_nexthop_ifindex_add (rib, ifindex);
break;
case NEXTHOP_TYPE_IPV4:
- nexthop.s_addr = stream_get_ipv4 (s);
- rib_nexthop_ipv4_add (rib, &nexthop, NULL);
+ nhop_addr.s_addr = stream_get_ipv4 (s);
+ nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL);
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+ {
+ label = (mpls_label_t)stream_getl (s);
+ nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label);
+ }
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
- nexthop.s_addr = stream_get_ipv4 (s);
+ nhop_addr.s_addr = stream_get_ipv4 (s);
ifindex = stream_getl (s);
- rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
+ rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex);
break;
case NEXTHOP_TYPE_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -1222,6 +1334,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
break;
case NEXTHOP_TYPE_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
+ /* For labeled-unicast, each nexthop is followed by label, but
+ * we don't care for delete.
+ */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+ stream_forward_getp (s, sizeof(u_int32_t));
nexthop_p = (union g_addr *)&nexthop;
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -1407,7 +1524,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
unsigned int i;
struct stream *s;
- struct in6_addr nexthop;
+ struct in6_addr nhop_addr;
struct rib *rib;
u_char message;
u_char nexthop_num;
@@ -1418,11 +1535,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
static struct in6_addr nexthops[MULTIPATH_NUM];
static unsigned int ifindices[MULTIPATH_NUM];
int ret;
+ static mpls_label_t labels[MULTIPATH_NUM];
+ mpls_label_t label;
+ struct nexthop *nexthop;
/* Get input stream. */
s = client->ibuf;
- memset (&nexthop, 0, sizeof (struct in6_addr));
+ memset (&nhop_addr, 0, sizeof (struct in6_addr));
/* Allocate new rib. */
rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
@@ -1471,10 +1591,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
switch (nexthop_type)
{
case NEXTHOP_TYPE_IPV6:
- stream_get (&nexthop, s, 16);
- if (nh_count < multipath_num) {
- nexthops[nh_count++] = nexthop;
- }
+ stream_get (&nhop_addr, s, 16);
+ if (nh_count < MULTIPATH_NUM)
+ {
+ /* For labeled-unicast, each nexthop is followed by label. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+ {
+ label = (mpls_label_t)stream_getl (s);
+ labels[nh_count++] = label;
+ }
+ nexthops[nh_count++] = nhop_addr;
+ }
break;
case NEXTHOP_TYPE_IFINDEX:
if (if_count < multipath_num) {
@@ -1492,9 +1619,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
if ((i < if_count) && ifindices[i])
- rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
+ nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
else
- rib_nexthop_ipv6_add (rib, &nexthops[i]);
+ nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]);
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+ nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]);
}
else {
if ((i < if_count) && ifindices[i])
@@ -1591,6 +1720,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
case NEXTHOP_TYPE_IPV6:
stream_get (&nexthop, s, 16);
+ /* For labeled-unicast, each nexthop is followed by label, but
+ * we don't care for delete.
+ */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+ stream_forward_getp (s, sizeof(u_int32_t));
pnexthop = (union g_addr *)&nexthop;
break;
case NEXTHOP_TYPE_IFINDEX:
@@ -1761,14 +1895,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
if (command == ZEBRA_MPLS_LABELS_ADD)
{
mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
- NULL, ifindex);
+ ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
}
else if (command == ZEBRA_MPLS_LABELS_DELETE)
{
- mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex);
+ mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
@@ -1975,6 +2109,9 @@ zebra_client_close (struct zserv *client)
/* Release Label Manager chunks */
release_daemon_chunks (client->proto, client->instance);
+ /* Cleanup any FECs registered by this client. */
+ zebra_mpls_cleanup_fecs_for_client (vrf_info_lookup(VRF_DEFAULT), client);
+
/* Close file descriptor. */
if (client->sock)
{
@@ -2263,6 +2400,12 @@ zebra_client_read (struct thread *thread)
case ZEBRA_RELEASE_LABEL_CHUNK:
zread_label_manager_request (command, client, vrf_id);
break;
+ case ZEBRA_FEC_REGISTER:
+ zserv_fec_register (client, sock, length);
+ break;
+ case ZEBRA_FEC_UNREGISTER:
+ zserv_fec_unregister (client, sock, length);
+ break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;
@@ -2446,11 +2589,12 @@ zebra_event (enum event event, int sock, struct zserv *client)
switch (event)
{
case ZEBRA_SERV:
- thread_add_read (zebrad.master, zebra_accept, client, sock);
+ thread_add_read(zebrad.master, zebra_accept, client, sock, NULL);
break;
case ZEBRA_READ:
- client->t_read =
- thread_add_read (zebrad.master, zebra_client_read, client, sock);
+ client->t_read = NULL;
+ thread_add_read(zebrad.master, zebra_client_read, client, sock,
+ &client->t_read);
break;
case ZEBRA_WRITE:
/**/