static int
nhlfe_del (zebra_nhlfe_t *snhlfe);
static int
-static_lsp_install (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);
+mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
+ enum lsp_types_t type);
static int
-static_lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t in_label,
- enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex);
-static int
-static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label);
+mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label);
static void
nhlfe_print (zebra_nhlfe_t *nhlfe, struct vty *vty);
static void
XFREE (MTYPE_NHLFE, nhlfe);
return NULL;
}
- nexthop_add_labels (nexthop, 1, &out_label);
+ nexthop_add_labels (nexthop, lsp_type, 1, &out_label);
nexthop->type = gtype;
switch (nexthop->type)
return 0;
}
-
-/*
- * Install/update a static NHLFE for an LSP in the forwarding table. This may
- * be a new LSP entry or a new NHLFE for an existing in-label or an update of
- * the out-label for an existing NHLFE (update case).
- */
static int
-static_lsp_install (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)
+mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
+ enum lsp_types_t type)
{
- struct hash *lsp_table;
- zebra_ile_t tmp_ile;
- zebra_lsp_t *lsp;
- zebra_nhlfe_t *nhlfe;
- char buf[BUFSIZ];
-
- /* Lookup table. */
- lsp_table = zvrf->lsp_table;
- if (!lsp_table)
- return -1;
-
- /* If entry is present, exit. */
- tmp_ile.in_label = in_label;
- lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
- if (!lsp)
- return -1;
- nhlfe = nhlfe_find (lsp, ZEBRA_LSP_STATIC, gtype, gate, ifname, ifindex);
- if (nhlfe)
- {
- struct nexthop *nh = nhlfe->nexthop;
-
- assert (nh);
- assert (nh->nh_label);
-
- /* Clear deleted flag (in case it was set) */
- UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
- if (nh->nh_label->label[0] == out_label)
- /* No change */
- return 0;
-
- if (IS_ZEBRA_DEBUG_MPLS)
- {
- nhlfe2str (nhlfe, buf, BUFSIZ);
- zlog_debug ("LSP in-label %u type %d nexthop %s "
- "out-label changed to %u (old %u)",
- in_label, ZEBRA_LSP_STATIC, buf,
- out_label, nh->nh_label->label[0]);
- }
-
- /* Update out label, trigger processing. */
- nh->nh_label->label[0] = out_label;
- }
- else
- {
- /* Add LSP entry to this nexthop */
- nhlfe = nhlfe_add (lsp, ZEBRA_LSP_STATIC, gtype, gate,
- ifname, ifindex, out_label);
- if (!nhlfe)
- return -1;
-
- if (IS_ZEBRA_DEBUG_MPLS)
- {
- nhlfe2str (nhlfe, buf, BUFSIZ);
- zlog_debug ("Add LSP in-label %u type %d nexthop %s "
- "out-label %u",
- in_label, ZEBRA_LSP_STATIC, buf,
- out_label);
- }
-
- lsp->addr_family = NHLFE_FAMILY (nhlfe);
- }
-
- /* Mark NHLFE, queue LSP for processing. */
- SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
- if (lsp_processq_add (lsp))
- return -1;
-
- return 0;
-}
-
-/*
- * Uninstall a particular static NHLFE in the forwarding table. If this is
- * the only NHLFE, the entire LSP forwarding entry has to be deleted.
- */
-static int
-static_lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t in_label,
- enum nexthop_types_t gtype, union g_addr *gate,
- char *ifname, ifindex_t ifindex)
-{
- struct hash *lsp_table;
- zebra_ile_t tmp_ile;
- zebra_lsp_t *lsp;
- zebra_nhlfe_t *nhlfe;
- char buf[BUFSIZ];
-
- /* Lookup table. */
- lsp_table = zvrf->lsp_table;
- if (!lsp_table)
- return -1;
-
- /* If entry is not present, exit. */
- tmp_ile.in_label = in_label;
- lsp = hash_lookup (lsp_table, &tmp_ile);
- if (!lsp)
- return 0;
- nhlfe = nhlfe_find (lsp, ZEBRA_LSP_STATIC, gtype, gate, ifname, ifindex);
- if (!nhlfe)
- return 0;
-
- if (IS_ZEBRA_DEBUG_MPLS)
- {
- nhlfe2str (nhlfe, buf, BUFSIZ);
- zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
- in_label, ZEBRA_LSP_STATIC, buf, nhlfe->flags);
- }
-
- /* Mark NHLFE for delete or directly delete, as appropriate. */
- if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
- {
- UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
- SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
- if (lsp_processq_add (lsp))
- return -1;
- }
- else
- {
- nhlfe_del (nhlfe);
-
- /* Free LSP entry if no other NHLFEs and not scheduled. */
- if (!lsp->nhlfe_list &&
- !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
- {
- if (IS_ZEBRA_DEBUG_MPLS)
- zlog_debug ("Free LSP in-label %u flags 0x%x",
- lsp->ile.in_label, lsp->flags);
-
- lsp = hash_release(lsp_table, &lsp->ile);
- if (lsp)
- XFREE(MTYPE_LSP, lsp);
- }
- }
- return 0;
-}
-
-/*
- * Uninstall all static NHLFEs for a particular LSP forwarding entry.
- * If no other NHLFEs exist, the entry would be deleted.
- */
-static int
-static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
-{
- struct hash *lsp_table;
- zebra_ile_t tmp_ile;
- zebra_lsp_t *lsp;
zebra_nhlfe_t *nhlfe, *nhlfe_next;
int schedule_lsp = 0;
char buf[BUFSIZ];
- /* Lookup table. */
- lsp_table = zvrf->lsp_table;
- if (!lsp_table)
- return -1;
-
- /* If entry is not present, exit. */
- tmp_ile.in_label = in_label;
- lsp = hash_lookup (lsp_table, &tmp_ile);
- if (!lsp || !lsp->nhlfe_list)
- return 0;
-
/* Mark NHLFEs for delete or directly delete, as appropriate. */
for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
{
nhlfe_next = nhlfe->next;
/* Skip non-static NHLFEs */
- if (nhlfe->type != ZEBRA_LSP_STATIC)
+ if (nhlfe->type != type)
continue;
if (IS_ZEBRA_DEBUG_MPLS)
{
nhlfe2str (nhlfe, buf, BUFSIZ);
zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
- in_label, ZEBRA_LSP_STATIC, buf, nhlfe->flags);
+ lsp->ile.in_label, type, buf, nhlfe->flags);
}
if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
return 0;
}
+/*
+ * Uninstall all static NHLFEs for a particular LSP forwarding entry.
+ * If no other NHLFEs exist, the entry would be deleted.
+ */
+static int
+mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
+{
+ struct hash *lsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_lsp_t *lsp;
+
+ /* Lookup table. */
+ lsp_table = zvrf->lsp_table;
+ if (!lsp_table)
+ return -1;
+
+ /* If entry is not present, exit. */
+ tmp_ile.in_label = in_label;
+ lsp = hash_lookup (lsp_table, &tmp_ile);
+ if (!lsp || !lsp->nhlfe_list)
+ return 0;
+
+ return mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_STATIC);
+}
+
static json_object *
nhlfe_json (zebra_nhlfe_t *nhlfe)
{
return buf;
}
+/*
+ * Install/uninstall a FEC-To-NHLFE (FTN) binding.
+ */
+int
+mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
+ struct prefix *prefix, union g_addr *gate, u_int8_t distance,
+ mpls_label_t out_label)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ struct nexthop *nexthop;
+
+ /* Lookup table. */
+ table = zebra_vrf_table (family2afi(prefix->family), SAFI_UNICAST, zvrf->vrf_id);
+ if (! table)
+ return -1;
+
+ /* Lookup existing route */
+ rn = route_node_get (table, prefix);
+ RNODE_FOREACH_RIB (rn, rib)
+ {
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+ if (rib->distance == distance)
+ break;
+ }
+
+ if (rib == NULL)
+ return -1;
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ switch (prefix->family)
+ {
+ case AF_INET:
+ if (nexthop->type != NEXTHOP_TYPE_IPV4 &&
+ nexthop->type != NEXTHOP_TYPE_IPV4_IFINDEX)
+ continue;
+ if (! IPV4_ADDR_SAME (&nexthop->gate.ipv4, &gate->ipv4))
+ continue;
+ goto found;
+ break;
+ case AF_INET6:
+ if (nexthop->type != NEXTHOP_TYPE_IPV6 &&
+ nexthop->type != NEXTHOP_TYPE_IPV6_IFINDEX)
+ continue;
+ if (! IPV6_ADDR_SAME (&nexthop->gate.ipv6, &gate->ipv6))
+ continue;
+ goto found;
+ break;
+ default:
+ break;
+ }
+ /* nexthop not found */
+ return -1;
+
+ found:
+ if (add)
+ nexthop_add_labels (nexthop, type, 1, &out_label);
+ else
+ nexthop_del_labels (nexthop);
+
+ SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+ SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+ rib_queue_add (rn);
+
+ return 0;
+}
+
+/*
+ * Install/update a NHLFE for an LSP in the forwarding table. This may be
+ * a new LSP entry or a new NHLFE for an existing in-label or an update of
+ * the out-label for an existing NHLFE (update case).
+ */
+int
+mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
+ mpls_label_t in_label, mpls_label_t out_label,
+ enum nexthop_types_t gtype, union g_addr *gate,
+ char *ifname, ifindex_t ifindex)
+{
+ struct hash *lsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_lsp_t *lsp;
+ zebra_nhlfe_t *nhlfe;
+ char buf[BUFSIZ];
+
+ /* Lookup table. */
+ lsp_table = zvrf->lsp_table;
+ if (!lsp_table)
+ return -1;
+
+ /* If entry is present, exit. */
+ tmp_ile.in_label = in_label;
+ lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
+ if (!lsp)
+ return -1;
+ nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+ if (nhlfe)
+ {
+ struct nexthop *nh = nhlfe->nexthop;
+
+ assert (nh);
+ assert (nh->nh_label);
+
+ /* Clear deleted flag (in case it was set) */
+ UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+ if (nh->nh_label->label[0] == out_label)
+ /* No change */
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ nhlfe2str (nhlfe, buf, BUFSIZ);
+ zlog_debug ("LSP in-label %u type %d nexthop %s "
+ "out-label changed to %u (old %u)",
+ in_label, type, buf,
+ out_label, nh->nh_label->label[0]);
+ }
+
+ /* Update out label, trigger processing. */
+ nh->nh_label->label[0] = out_label;
+ }
+ else
+ {
+ /* Add LSP entry to this nexthop */
+ nhlfe = nhlfe_add (lsp, type, gtype, gate,
+ ifname, ifindex, out_label);
+ if (!nhlfe)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ nhlfe2str (nhlfe, buf, BUFSIZ);
+ zlog_debug ("Add LSP in-label %u type %d nexthop %s "
+ "out-label %u", in_label, type, buf, out_label);
+ }
+
+ lsp->addr_family = NHLFE_FAMILY (nhlfe);
+ }
+
+ /* Mark NHLFE, queue LSP for processing. */
+ SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
+ if (lsp_processq_add (lsp))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Uninstall a particular NHLFE in the forwarding table. If this is
+ * the only NHLFE, the entire LSP forwarding entry has to be deleted.
+ */
+int
+mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
+ mpls_label_t in_label, enum nexthop_types_t gtype,
+ union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+ struct hash *lsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_lsp_t *lsp;
+ zebra_nhlfe_t *nhlfe;
+ char buf[BUFSIZ];
+
+ /* Lookup table. */
+ lsp_table = zvrf->lsp_table;
+ if (!lsp_table)
+ return -1;
+
+ /* If entry is not present, exit. */
+ tmp_ile.in_label = in_label;
+ lsp = hash_lookup (lsp_table, &tmp_ile);
+ if (!lsp)
+ return 0;
+ nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+ if (!nhlfe)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ nhlfe2str (nhlfe, buf, BUFSIZ);
+ zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
+ in_label, type, buf, nhlfe->flags);
+ }
+
+ /* Mark NHLFE for delete or directly delete, as appropriate. */
+ if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
+ {
+ UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+ SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+ if (lsp_processq_add (lsp))
+ return -1;
+ }
+ else
+ {
+ nhlfe_del (nhlfe);
+
+ /* Free LSP entry if no other NHLFEs and not scheduled. */
+ if (!lsp->nhlfe_list &&
+ !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Free LSP in-label %u flags 0x%x",
+ lsp->ile.in_label, lsp->flags);
+
+ lsp = hash_release(lsp_table, &lsp->ile);
+ if (lsp)
+ XFREE(MTYPE_LSP, lsp);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
+ * If no other NHLFEs exist, the entry would be deleted.
+ */
+void
+mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt)
+{
+ zebra_lsp_t *lsp;
+ struct hash *lsp_table;
+
+ lsp = (zebra_lsp_t *) backet->data;
+ if (!lsp || !lsp->nhlfe_list)
+ return;
+
+ lsp_table = ctxt;
+ if (!lsp_table)
+ return;
+
+ mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_LDP);
+}
+
+/*
+ * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ */
+void
+mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ struct nexthop *nexthop;
+ int update;
+
+ /* Process routes of interested address-families. */
+ table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf->vrf_id);
+ if (!table)
+ return;
+
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ {
+ update = 0;
+ RNODE_FOREACH_RIB (rn, rib)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ if (nexthop->nh_label_type == ZEBRA_LSP_LDP)
+ {
+ nexthop_del_labels (nexthop);
+ SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+ SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+ update = 1;
+ }
+
+ if (update)
+ rib_queue_add (rn);
+ }
+}
+
/*
* Check that the label values used in LSP creation are consistent. The
* main criteria is that if there is ECMP, the label operation must still
}
/* (Re)Install LSP in the main table. */
- if (static_lsp_install (zvrf, in_label, out_label, gtype,
- gate, ifname, ifindex))
+ if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
+ gate, ifname, ifindex))
return -1;
return 0;
zlog_debug ("Del static LSP in-label %u", in_label);
/* Uninstall entire LSP from the main table. */
- static_lsp_uninstall_all (zvrf, in_label);
+ mpls_static_lsp_uninstall_all (zvrf, in_label);
/* Delete all static NHLFEs */
snhlfe_del_all (slsp);
}
/* Uninstall LSP from the main table. */
- static_lsp_uninstall (zvrf, in_label, gtype,
- gate, ifname, ifindex);
+ mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate,
+ ifname, ifindex);
/* Delete static LSP NHLFE */
snhlfe_del (snhlfe);
#include "zebra/interface.h"
#include "zebra/zebra_ptm.h"
#include "zebra/rtadv.h"
+#include "zebra/zebra_mpls.h"
/* Event list of zebra. */
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
return 0;
}
+static void
+zread_mpls_labels (int command, struct zserv *client, u_short length,
+ vrf_id_t vrf_id)
+{
+ struct stream *s;
+ enum lsp_types_t type;
+ struct prefix prefix;
+ enum nexthop_types_t gtype;
+ union g_addr gate;
+ 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;
+
+ /* Get data. */
+ type = stream_getc (s);
+ prefix.family = stream_getl (s);
+ switch (prefix.family)
+ {
+ case AF_INET:
+ prefix.u.prefix4.s_addr = stream_get_ipv4 (s);
+ prefix.prefixlen = stream_getc (s);
+ gtype = NEXTHOP_TYPE_IPV4;
+ gate.ipv4.s_addr = stream_get_ipv4 (s);
+ break;
+ case AF_INET6:
+ stream_get (&prefix.u.prefix6, s, 16);
+ prefix.prefixlen = stream_getc (s);
+ gtype = NEXTHOP_TYPE_IPV6;
+ stream_get (&gate.ipv6, s, 16);
+ break;
+ default:
+ return;
+ }
+ distance = stream_getc (s);
+ in_label = stream_getl (s);
+ out_label = stream_getl (s);
+
+ if (command == ZEBRA_MPLS_LABELS_ADD)
+ {
+ mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
+ NULL, 0);
+ if (out_label != MPLS_IMP_NULL_LABEL)
+ mpls_ftn_update (1, zvrf, type, &prefix, &gate, distance, out_label);
+ }
+ else if (command == ZEBRA_MPLS_LABELS_DELETE)
+ {
+ mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, 0);
+ if (out_label != MPLS_IMP_NULL_LABEL)
+ mpls_ftn_update (0, zvrf, type, &prefix, &gate, distance, out_label);
+ }
+}
+
/* Cleanup registered nexthops (across VRFs) upon client disconnect. */
static void
zebra_client_close_cleanup_rnh (struct zserv *client)
zebra_cleanup_rnh_client(zvrf->vrf_id, AF_INET6, client, RNH_NEXTHOP_TYPE);
zebra_cleanup_rnh_client(zvrf->vrf_id, AF_INET, client, RNH_IMPORT_CHECK_TYPE);
zebra_cleanup_rnh_client(zvrf->vrf_id, AF_INET6, client, RNH_IMPORT_CHECK_TYPE);
+ if (client->proto == ZEBRA_ROUTE_LDP)
+ {
+ hash_iterate(zvrf->lsp_table, mpls_ldp_lsp_uninstall_all,
+ zvrf->lsp_table);
+ mpls_ldp_ftn_uninstall_all (zvrf, AFI_IP);
+ mpls_ldp_ftn_uninstall_all (zvrf, AFI_IP6);
+ }
}
}
}
case ZEBRA_INTERFACE_DISABLE_RADV:
zebra_interface_radv_set (client, sock, length, zvrf, 0);
break;
+ case ZEBRA_MPLS_LABELS_ADD:
+ case ZEBRA_MPLS_LABELS_DELETE:
+ zread_mpls_labels (command, client, length, vrf_id);
+ break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;