summaryrefslogtreecommitdiff
path: root/zebra/zapi_msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zapi_msg.c')
-rw-r--r--zebra/zapi_msg.c195
1 files changed, 127 insertions, 68 deletions
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index fa6a2f62ec..826d31ef37 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1749,88 +1749,146 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS)
vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf));
}
-static void zread_mpls_labels(ZAPI_HANDLER_ARGS)
+/*
+ * Handle request to create an MPLS LSP.
+ *
+ * A single message can fully specify an LSP with multiple nexthops.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is
+ * updated to use the received label(s).
+ */
+static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS)
{
struct stream *s;
- enum lsp_types_t type;
- struct prefix prefix;
- enum nexthop_types_t gtype;
- union g_addr gate;
- ifindex_t ifindex;
- mpls_label_t in_label, out_label;
- uint8_t distance;
+ struct zapi_labels zl;
/* Get input stream. */
s = msg;
+ if (zapi_labels_decode(s, &zl) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_labels sent",
+ __PRETTY_FUNCTION__);
+ return;
+ }
- /* Get data. */
- STREAM_GETC(s, type);
- STREAM_GETL(s, prefix.family);
- switch (prefix.family) {
- case AF_INET:
- STREAM_GET(&prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
- STREAM_GETC(s, prefix.prefixlen);
- if (prefix.prefixlen > IPV4_MAX_BITLEN) {
- zlog_debug(
- "%s: Specified prefix length %d is greater than a v4 address can support",
- __PRETTY_FUNCTION__, prefix.prefixlen);
- return;
- }
- STREAM_GET(&gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN);
- break;
- case AF_INET6:
- STREAM_GET(&prefix.u.prefix6, s, 16);
- STREAM_GETC(s, prefix.prefixlen);
- if (prefix.prefixlen > IPV6_MAX_BITLEN) {
- zlog_debug(
- "%s: Specified prefix length %d is greater than a v6 address can support",
- __PRETTY_FUNCTION__, prefix.prefixlen);
- return;
- }
- STREAM_GET(&gate.ipv6, s, 16);
- break;
- default:
- zlog_debug("%s: Specified AF %d is not supported for this call",
- __PRETTY_FUNCTION__, prefix.family);
+ if (!mpls_enabled)
return;
+
+ for (int i = 0; i < zl.nexthop_num; i++) {
+ struct zapi_nexthop_label *znh;
+
+ znh = &zl.nexthops[i];
+ mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label,
+ znh->type, &znh->address, znh->ifindex);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix,
+ znh->type, &znh->address, znh->ifindex,
+ zl.route.type, zl.route.instance,
+ znh->label);
}
- STREAM_GETL(s, ifindex);
- STREAM_GETC(s, distance);
- STREAM_GETL(s, in_label);
- STREAM_GETL(s, out_label);
+}
- switch (prefix.family) {
- case AF_INET:
- if (ifindex)
- gtype = NEXTHOP_TYPE_IPV4_IFINDEX;
- else
- gtype = NEXTHOP_TYPE_IPV4;
- break;
- case AF_INET6:
- if (ifindex)
- gtype = NEXTHOP_TYPE_IPV6_IFINDEX;
- else
- gtype = NEXTHOP_TYPE_IPV6;
- break;
- default:
+/*
+ * Handle request to delete an MPLS LSP.
+ *
+ * An LSP is identified by its type and local label. When the received message
+ * doesn't contain any nexthop, the whole LSP is deleted. Otherwise, only the
+ * listed LSP nexthops (aka NHLFEs) are deleted.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the labels of the specified
+ * FEC (route) nexthops are deleted.
+ */
+static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_labels zl;
+
+ /* Get input stream. */
+ s = msg;
+ if (zapi_labels_decode(s, &zl) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_labels sent",
+ __PRETTY_FUNCTION__);
return;
}
if (!mpls_enabled)
return;
- if (hdr->command == ZEBRA_MPLS_LABELS_ADD) {
- mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
- ifindex);
- mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex,
- distance, out_label);
- } else if (hdr->command == ZEBRA_MPLS_LABELS_DELETE) {
- mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
- mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex,
- distance, out_label);
+ if (zl.nexthop_num > 0) {
+ for (int i = 0; i < zl.nexthop_num; i++) {
+ struct zapi_nexthop_label *znh;
+
+ znh = &zl.nexthops[i];
+ mpls_lsp_uninstall(zvrf, zl.type, zl.local_label,
+ znh->type, &znh->address,
+ znh->ifindex);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_update(0, zvrf, zl.type,
+ &zl.route.prefix, znh->type,
+ &znh->address, znh->ifindex,
+ zl.route.type,
+ zl.route.instance, znh->label);
+ }
+ } else {
+ mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
+ zl.route.type, zl.route.instance);
+ }
+}
+
+/*
+ * Handle request to add an MPLS LSP or change an existing one.
+ *
+ * A single message can fully specify an LSP with multiple nexthops.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is
+ * updated to use the received label(s).
+ *
+ * NOTE: zebra will use route replace semantics (make-before-break) to update
+ * the LSP in the forwarding plane if that's supported by the underlying
+ * platform.
+ */
+static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_labels zl;
+
+ /* Get input stream. */
+ s = msg;
+ if (zapi_labels_decode(s, &zl) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_labels sent",
+ __PRETTY_FUNCTION__);
+ return;
+ }
+
+ if (!mpls_enabled)
+ return;
+
+ mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+ mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
+ zl.route.type, zl.route.instance);
+
+ for (int i = 0; i < zl.nexthop_num; i++) {
+ struct zapi_nexthop_label *znh;
+
+ znh = &zl.nexthops[i];
+ mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label,
+ znh->type, &znh->address, znh->ifindex);
+
+ if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) {
+ mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix,
+ znh->type, &znh->address, znh->ifindex,
+ zl.route.type, zl.route.instance,
+ znh->label);
+ }
}
-stream_failure:
- return;
}
/* Send response to a table manager connect request to client */
@@ -2455,8 +2513,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_INTERFACE_ENABLE_RADV] = NULL,
[ZEBRA_INTERFACE_DISABLE_RADV] = NULL,
#endif
- [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels,
- [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels,
+ [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add,
+ [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete,
+ [ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace,
[ZEBRA_IPMR_ROUTE_STATS] = zebra_ipmr_route_stats,
[ZEBRA_LABEL_MANAGER_CONNECT] = zread_label_manager_request,
[ZEBRA_LABEL_MANAGER_CONNECT_ASYNC] = zread_label_manager_request,