diff options
| author | Renato Westphal <renato@opensourcerouting.org> | 2016-06-01 14:19:30 -0300 |
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-09-23 09:31:12 -0400 |
| commit | ce54994727bf237e0f89168d6818b04ea79f090d (patch) | |
| tree | bd363cc85b7031136d4d8d51407ed7bd8c737cc3 | |
| parent | 4fcbf6e2d9a3c1f13d142e9b0dbd2369ec2b0bda (diff) | |
mpls: add support for LDP LSPs
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
| -rw-r--r-- | ldpd/ldp_zebra.c | 54 | ||||
| -rw-r--r-- | lib/log.c | 2 | ||||
| -rw-r--r-- | lib/mpls.h | 9 | ||||
| -rw-r--r-- | lib/nexthop.c | 14 | ||||
| -rw-r--r-- | lib/nexthop.h | 5 | ||||
| -rw-r--r-- | lib/zebra.h | 2 | ||||
| -rw-r--r-- | zebra/zebra_mpls.c | 486 | ||||
| -rw-r--r-- | zebra/zebra_mpls.h | 52 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_static.c | 4 | ||||
| -rw-r--r-- | zebra/zserv.c | 71 |
11 files changed, 500 insertions, 201 deletions
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 41ff47fba3..6e19e4f607 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -28,6 +28,7 @@ #include "command.h" #include "network.h" #include "linklist.h" +#include "mpls.h" #include "ldpd.h" #include "ldpe.h" @@ -38,6 +39,7 @@ static void ifp2kif(struct interface *, struct kif *); static void ifc2kaddr(struct interface *, struct connected *, struct kaddr *); +static int zebra_send_mpls_labels(int, struct kroute *); static int ldp_router_id_update(int, struct zclient *, zebra_size_t, vrf_id_t); static int ldp_interface_add(int, struct zclient *, zebra_size_t, @@ -89,18 +91,62 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) } } +static int +zebra_send_mpls_labels(int cmd, struct kroute *kr) +{ + struct stream *s; + + if (kr->local_label < MPLS_LABEL_RESERVED_MAX || + kr->remote_label == NO_LABEL) + return (0); + + debug_zebra_out("prefix %s/%u nexthop %s labels %s/%s (%s)", + log_addr(kr->af, &kr->prefix), kr->prefixlen, + log_addr(kr->af, &kr->nexthop), log_label(kr->local_label), + log_label(kr->remote_label), + (cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete"); + + /* Reset stream. */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, cmd, VRF_DEFAULT); + stream_putc(s, ZEBRA_LSP_LDP); + stream_putl(s, kr->af); + switch (kr->af) { + case AF_INET: + stream_put_in_addr(s, &kr->prefix.v4); + stream_putc(s, kr->prefixlen); + stream_put_in_addr(s, &kr->nexthop.v4); + break; + case AF_INET6: + stream_write(s, (u_char *)&kr->prefix.v6, 16); + stream_putc(s, kr->prefixlen); + stream_write(s, (u_char *)&kr->nexthop.v6, 16); + break; + default: + fatalx("kr_change: unknown af"); + } + stream_putc(s, kr->priority); + stream_putl(s, kr->local_label); + stream_putl(s, kr->remote_label); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return (zclient_send_message(zclient)); +} + int kr_change(struct kroute *kr) { - /* TODO */ - return (0); + return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr)); } int kr_delete(struct kroute *kr) { - /* TODO */ - return (0); + return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr)); } int @@ -939,6 +939,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_INTERFACE_ENABLE_RADV), DESC_ENTRY (ZEBRA_INTERFACE_DISABLE_RADV), DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB), + DESC_ENTRY (ZEBRA_MPLS_LABELS_ADD), + DESC_ENTRY (ZEBRA_MPLS_LABELS_DELETE), }; #undef DESC_ENTRY diff --git a/lib/mpls.h b/lib/mpls.h index 5a67b915d1..1f77aaa536 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -75,8 +75,17 @@ typedef unsigned int mpls_lse_t; /* MPLS label value as a 32-bit (mostly we only care about the label value). */ typedef unsigned int mpls_label_t; +#define MPLS_NO_LABEL 0xFFFFFFFF #define MPLS_INVALID_LABEL 0xFFFFFFFF +/* LSP types. */ +enum lsp_types_t +{ + ZEBRA_LSP_NONE = 0, /* No LSP. */ + ZEBRA_LSP_STATIC = 1, /* Static LSP. */ + ZEBRA_LSP_LDP = 2 /* LDP LSP. */ +}; + /* Functions for basic label operations. */ /* Encode a label stack entry from fields; convert to network byte-order as diff --git a/lib/nexthop.c b/lib/nexthop.c index 8e775b68be..01771e253c 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -130,8 +130,8 @@ copy_nexthops (struct nexthop **tnh, struct nexthop *nh) memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); if (nh->nh_label) - nexthop_add_labels (nexthop, nh->nh_label->num_labels, - &nh->nh_label->label[0]); + nexthop_add_labels (nexthop, nh->nh_label_type, + nh->nh_label->num_labels, &nh->nh_label->label[0]); nexthop_add(tnh, nexthop); if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -164,12 +164,13 @@ nexthops_free (struct nexthop *nexthop) /* Update nexthop with label information. */ void -nexthop_add_labels (struct nexthop *nexthop, u_int8_t num_labels, - mpls_label_t *label) +nexthop_add_labels (struct nexthop *nexthop, enum lsp_types_t type, + u_int8_t num_labels, mpls_label_t *label) { struct nexthop_label *nh_label; int i; + nexthop->nh_label_type = type; nh_label = XCALLOC (MTYPE_NH_LABEL, sizeof (struct nexthop_label)); nh_label->num_labels = num_labels; for (i = 0; i < num_labels; i++) @@ -182,7 +183,10 @@ void nexthop_del_labels (struct nexthop *nexthop) { if (nexthop->nh_label) - XFREE (MTYPE_NH_LABEL, nexthop->nh_label); + { + XFREE (MTYPE_NH_LABEL, nexthop->nh_label); + nexthop->nh_label_type = ZEBRA_LSP_NONE; + } } const char * diff --git a/lib/nexthop.h b/lib/nexthop.h index c06dfe0e25..e66e0eee20 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -85,6 +85,9 @@ struct nexthop * Only one level of recursive resolution is currently supported. */ struct nexthop *resolved; + /* Type of label(s), if any */ + enum lsp_types_t nh_label_type; + /* Label(s) associated with this nexthop. */ struct nexthop_label *nh_label; }; @@ -109,7 +112,7 @@ void copy_nexthops (struct nexthop **tnh, struct nexthop *nh); void nexthop_free (struct nexthop *nexthop); void nexthops_free (struct nexthop *nexthop); -void nexthop_add_labels (struct nexthop *, u_int8_t, mpls_label_t *); +void nexthop_add_labels (struct nexthop *, enum lsp_types_t, u_int8_t, mpls_label_t *); void nexthop_del_labels (struct nexthop *); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); diff --git a/lib/zebra.h b/lib/zebra.h index d7a441c2e9..da069d1dfa 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -422,6 +422,8 @@ typedef enum { ZEBRA_INTERFACE_DISABLE_RADV, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, ZEBRA_INTERFACE_LINK_PARAMS, + ZEBRA_MPLS_LABELS_ADD, + ZEBRA_MPLS_LABELS_DELETE, } zebra_message_types_t; /* Marker value used in new Zserv, in the byte location corresponding diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 3e84114772..8f18f326d1 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -99,15 +99,10 @@ nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, 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 @@ -684,7 +679,7 @@ nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type, 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) @@ -746,190 +741,28 @@ nhlfe_del (zebra_nhlfe_t *nhlfe) 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)) @@ -965,6 +798,31 @@ static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label) 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) { @@ -1395,6 +1253,274 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, } /* + * 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 * be consistent - i.e., all paths either do a swap or do PHP. This is due @@ -1511,8 +1637,8 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label, } /* (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; @@ -1553,7 +1679,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, 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); @@ -1574,8 +1700,8 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label, } /* 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); diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 11949c9313..7c672fa433 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -53,13 +53,6 @@ typedef struct zebra_slsp_t_ zebra_slsp_t; typedef struct zebra_nhlfe_t_ zebra_nhlfe_t; typedef struct zebra_lsp_t_ zebra_lsp_t; -/* LSP types. */ -enum lsp_types_t -{ - ZEBRA_LSP_INVALID = 0, /* Invalid. */ - ZEBRA_LSP_STATIC = 1, /* Static LSP. */ -}; - /* * (Outgoing) nexthop label forwarding entry configuration */ @@ -172,6 +165,47 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels, char *buf, int len); /* + * 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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +/* * 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 * be consistent - i.e., all paths either do a swap or do PHP. This is due @@ -282,7 +316,7 @@ lsp_type_from_rib_type (int rib_type) case ZEBRA_ROUTE_STATIC: return ZEBRA_LSP_STATIC; default: - return ZEBRA_LSP_INVALID; + return ZEBRA_LSP_NONE; } } @@ -294,6 +328,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type) { case ZEBRA_LSP_STATIC: return "Static"; + case ZEBRA_LSP_LDP: + return "LDP"; default: return "Unknown"; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f79dfafa5e..f57c0b5d67 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -205,7 +205,7 @@ rib_copy_nexthops (struct rib *rib, struct nexthop *nh) memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); if (nh->nh_label) - nexthop_add_labels (nexthop, nh->nh_label->num_labels, + nexthop_add_labels (nexthop, nh->nh_label_type, nh->nh_label->num_labels, &nh->nh_label->label[0]); rib_nexthop_add(rib, nexthop); if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index fddc9d54c8..f2362e6871 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -98,7 +98,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro } /* Update label(s), if present. */ if (si->snh_label.num_labels) - nexthop_add_labels (nexthop, si->snh_label.num_labels, + nexthop_add_labels (nexthop, ZEBRA_LSP_STATIC, si->snh_label.num_labels, &si->snh_label.label[0]); if (IS_ZEBRA_DEBUG_RIB) @@ -162,7 +162,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro } /* Update label(s), if present. */ if (si->snh_label.num_labels) - nexthop_add_labels (nexthop, si->snh_label.num_labels, + nexthop_add_labels (nexthop, ZEBRA_LSP_STATIC, si->snh_label.num_labels, &si->snh_label.label[0]); /* Save the flags of this static routes (reject, blackhole) */ diff --git a/zebra/zserv.c b/zebra/zserv.c index e617ae28a2..4c68f6acb9 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -52,6 +52,7 @@ #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 }; @@ -1630,6 +1631,65 @@ zread_vrf_unregister (struct zserv *client, u_short length, struct zebra_vrf *zv 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) @@ -1645,6 +1705,13 @@ 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); + } } } } @@ -1926,6 +1993,10 @@ zebra_client_read (struct thread *thread) 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; |
