/* static function declarations */
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client);
+static void
+fec_update_clients (zebra_fec_t *fec);
static void
fec_print (zebra_fec_t *fec, struct vty *vty);
static zebra_fec_t *
/* Static functions */
+/*
+ * Inform about FEC to a registered client.
+ */
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client)
+{
+ struct stream *s;
+ struct route_node *rn;
+
+ rn = fec->rn;
+
+ /* Get output stream. */
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
+
+ stream_putw(s, rn->p.family);
+ stream_put_prefix (s, &rn->p);
+ stream_putl(s, fec->label);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ return zebra_server_send_message(client);
+}
+
+/*
+ * Update all registered clients about this FEC. Caller should've updated
+ * FEC and ensure no duplicate updates.
+ */
+static void
+fec_update_clients (zebra_fec_t *fec)
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Update client %s", zebra_route_string(client->proto));
+ fec_send(fec, client);
+ }
+}
+
+
/*
* Print a FEC-label binding entry.
*/
fec_print (zebra_fec_t *fec, struct vty *vty)
{
struct route_node *rn;
+ struct listnode *node;
+ struct zserv *client;
char buf[BUFSIZ];
rn = fec->rn;
vty_out(vty, "%s%s", buf, VTY_NEWLINE);
vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
vty_out(vty, "%s", VTY_NEWLINE);
+ if (!list_isempty(fec->client_list))
+ {
+ vty_out(vty, " Client list:");
+ for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+ vty_out(vty, " %s(fd %d)",
+ zebra_route_string(client->proto), client->sock);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
}
/*
}
/*
- * Add a FEC.
+ * Add a FEC. This may be upon a client registering for a binding
+ * or when a binding is configured.
*/
static zebra_fec_t *
fec_add (struct route_table *table, struct prefix *p,
rn->info = fec;
fec->rn = rn;
fec->label = label;
+ fec->client_list = list_new();
}
else
route_unlock_node (rn); /* for the route_node_get */
}
/*
- * Delete a FEC.
+ * Delete a FEC. This may be upon the last client deregistering for
+ * a FEC and no binding exists or when the binding is deleted and there
+ * are no registered clients.
*/
static int
fec_del (zebra_fec_t *fec)
{
+ list_free (fec->client_list);
fec->rn->info = NULL;
route_unlock_node (fec->rn);
XFREE (MTYPE_FEC, fec);
return buf;
}
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+ char buf[BUFSIZ];
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ prefix2str(p, buf, BUFSIZ);
+
+ /* Locate FEC */
+ fec = fec_find (table, p);
+ if (!fec)
+ {
+ fec = fec_add (table, p, MPLS_INVALID_LABEL, 0);
+ if (!fec)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_err("Failed to add FEC %s upon register, client %s",
+ buf, zebra_route_string(client->proto));
+ return -1;
+ }
+ }
+ else
+ {
+ if (listnode_lookup(fec->client_list, client))
+ /* Duplicate register */
+ return 0;
+ }
+
+ listnode_add (fec->client_list, client);
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug("FEC %s registered by client %s",
+ buf, zebra_route_string(client->proto));
+
+ if (fec->label != MPLS_INVALID_LABEL)
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Update client label %u", fec->label);
+ fec_send (fec, client);
+ }
+
+ return 0;
+}
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client)
+{
+ struct route_table *table;
+ zebra_fec_t *fec;
+ char buf[BUFSIZ];
+
+ table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+ if (!table)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ prefix2str(p, buf, BUFSIZ);
+
+ fec = fec_find (table, p);
+ if (!fec)
+ {
+ prefix2str(p, buf, BUFSIZ);
+ zlog_err("Failed to find FEC %s upon unregister, client %s",
+ buf, zebra_route_string(client->proto));
+ return -1;
+ }
+
+ listnode_delete(fec->client_list, client);
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug("FEC %s unregistered by client %s",
+ buf, zebra_route_string(client->proto));
+
+ if (list_isempty(fec->client_list) && (fec->label == MPLS_INVALID_LABEL))
+ fec_del (fec);
+
+ return 0;
+}
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+ struct route_node *rn;
+ zebra_fec_t *fec;
+ struct listnode *node;
+ struct zserv *fec_client;
+ int af;
+
+ for (af = AFI_IP; af < AFI_MAX; af++)
+ {
+ if (zvrf->fec_table[af] == NULL)
+ continue;
+
+ for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+ {
+ fec = rn->info;
+ if (!fec || list_isempty(fec->client_list))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, fec_client))
+ {
+ if (fec_client == client)
+ {
+ listnode_delete(fec->client_list, fec_client);
+ if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+ list_isempty(fec->client_list))
+ fec_del (fec);
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/*
* Return FEC (if any) to which this label is bound.
* Note: Only works for per-prefix binding and when the label is not
}
/*
- * Add static FEC to label binding.
- */
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them.
+*/
int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
mpls_label_t in_label)
/* Duplicate config */
return 0;
+ /* Label change, update clients. */
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug ("Update fec %s new label %u", buf, in_label);
fec->label = in_label;
+ fec_update_clients (fec);
}
return ret;
}
/*
- * Remove static FEC to label binding.
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients
*/
int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
zlog_debug ("Delete fec %s", buf);
}
- fec_del (fec);
+ fec->flags &= ~FEC_FLAG_CONFIGURED;
+ fec->label = MPLS_INVALID_LABEL;
+
+ /* If no client exists, just delete the FEC. */
+ if (list_isempty(fec->client_list))
+ {
+ fec_del (fec);
+ return 0;
+ }
+
+ fec_update_clients (fec);
+
return 0;
}
/* Flags. */
u_int32_t flags;
#define FEC_FLAG_CONFIGURED (1 << 0)
+
+ /* Clients interested in this FEC. */
+ struct list *client_list;
};
/* Function declarations. */
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
char *buf, int len);
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client);
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client);
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client);
+
/*
* Return FEC (if any) to which this label is bound.
* Note: Only works for per-prefix binding and when the label is not
zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
/*
- * Add static FEC to label binding.
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them.
*/
int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
mpls_label_t in_label);
/*
- * Remove static FEC to label binding.
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients.
*/
int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
int mpls_kernel_init (void) { return -1; };
+
+int mpls_enabled;
+
+char *
+mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
+ char *buf, int len)
+{
+ return NULL;
+}
+
+int
+mpls_str2label (const char *label_str, u_int8_t *num_labels,
+ mpls_label_t *labels)
+{
+ return 0;
+}
+
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
+ u_char use_json)
+{
+}
+
+void
+zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
+{
+}
+
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+int
+zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
+ mpls_label_t out_label, enum nexthop_types_t gtype,
+ union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
+ mpls_label_t out_label, enum nexthop_types_t gtype,
+ union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
+ enum nexthop_types_t gtype, union g_addr *gate,
+ char *ifname, ifindex_t ifindex)
+{
+ return 0;
+}
+
+void
+zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_close_tables (struct zebra_vrf *zvrf)
+{
+}
+
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ return NULL;
+}
+
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+ mpls_label_t in_label)
+{
+ return 0;
+}
+
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
+{
+ return 0;
+}
+
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
+{
+}
+
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client)
+{
+ return 0;
+}
+
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+ struct zserv *client)
+{
+ return 0;
+}
+
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+ return 0;
+}
+
return 0;
}
+/* 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;
+
+ s = client->ibuf;
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0; // unexpected
+
+ while (l < length)
+ {
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ l += 5;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ zebra_mpls_fec_register (zvrf, &p, 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;
+
+ s = client->ibuf;
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0; // unexpected
+
+ while (l < length)
+ {
+ p.family = stream_getw(s);
+ 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.
/* 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)
{
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;