summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_label.c
diff options
context:
space:
mode:
authorDon Slice <dslice@cumulusnetworks.com>2017-03-09 15:54:20 +0100
committerDonald Sharp <sharpd@cumulusnetworks.com>2017-04-06 16:32:07 +0200
commitcd1964ff38bdbd2b5d36d0a0d89890e9d1bb2a50 (patch)
tree204d8be9bf9c213e4a895b1d335fafc8cc4c7d3f /bgpd/bgp_label.c
parentbgpd: labeled unicast config (diff)
downloadfrr-cd1964ff38bdbd2b5d36d0a0d89890e9d1bb2a50.tar.xz
frr-cd1964ff38bdbd2b5d36d0a0d89890e9d1bb2a50.zip
bgpd: labeled unicast processing
Implement support for negotiating IPv4 or IPv6 labeled-unicast address family, exchanging prefixes and installing them in the routing table, as well as interactions with Zebra for FEC registration. This is the implementation of RFC 3107. Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
Diffstat (limited to 'bgpd/bgp_label.c')
-rw-r--r--bgpd/bgp_label.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
new file mode 100644
index 000000000..283afbc92
--- /dev/null
+++ b/bgpd/bgp_label.c
@@ -0,0 +1,318 @@
+/* BGP carrying label information
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "thread.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
+#include "log.h"
+#include "memory.h"
+#include "nexthop.h"
+#include "mpls.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_label.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_debug.h"
+
+extern struct zclient *zclient;
+
+int
+bgp_parse_fec_update (void)
+{
+ struct stream *s;
+ struct bgp_node *rn;
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct prefix p;
+ u_int32_t label;
+ afi_t afi;
+ safi_t safi;
+
+ s = zclient->ibuf;
+
+ memset(&p, 0, sizeof(struct prefix));
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ label = stream_getl(s);
+
+ /* hack for the bgp instance & SAFI = have to send/receive it */
+ afi = family2afi(p.family);
+ safi = SAFI_LABELED_UNICAST;
+ bgp = bgp_get_default();
+ if (!bgp)
+ {
+ zlog_debug("no default bgp instance");
+ return -1;
+ }
+
+ table = bgp->rib[afi][safi];
+ if (!table)
+ {
+ zlog_debug("no %u labeled-unicast table", p.family);
+ return -1;
+ }
+ rn = bgp_node_lookup(table, &p);
+ if (!rn)
+ {
+ zlog_debug("no node for the prefix");
+ return -1;
+ }
+
+ /* treat it as implicit withdraw - the label is invalid */
+ if (label == MPLS_INVALID_LABEL)
+ bgp_unset_valid_label(rn->local_label);
+ else
+ {
+ label_ntop(label, 1, rn->local_label);
+ bgp_set_valid_label(rn->local_label);
+ }
+ SET_FLAG(rn->flags, BGP_NODE_LABEL_CHANGED);
+ bgp_unlock_node (rn);
+ bgp_process (bgp, rn, afi, safi);
+ return 1;
+}
+
+u_char *
+bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to,
+ afi_t afi, safi_t safi)
+{
+ struct peer *from;
+ u_char *remote_label;
+ int reflect;
+
+ if (!rn || !ri || !to)
+ return NULL;
+
+ remote_label = ri->extra ? ri->extra->tag : NULL;
+ from = ri->peer;
+ reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
+
+ if (reflect && !CHECK_FLAG(to->af_flags[afi][safi],
+ PEER_FLAG_FORCE_NEXTHOP_SELF))
+ return remote_label;
+
+ if (CHECK_FLAG(to->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))
+ return remote_label;
+
+ return rn->local_label;
+}
+
+void
+bgp_reg_dereg_for_label (struct bgp_node *rn, int reg)
+{
+ struct stream *s;
+ struct prefix *p;
+ int command;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ p = &(rn->p);
+ s = zclient->obuf;
+ stream_reset (s);
+ command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
+ zclient_create_header (s, command, VRF_DEFAULT);
+ stream_putw(s, PREFIX_FAMILY(p));
+ stream_put_prefix(s, p);
+ stream_putw_at (s, 0, stream_get_endp (s));
+ zclient_send_message(zclient);
+
+ return;
+}
+
+static int
+bgp_nlri_get_labels (struct peer *peer, u_char *pnt, u_char plen,
+ u_char label[])
+{
+ u_char *data = pnt;
+ u_char *lim = pnt + plen;
+ u_char llen = 0;
+
+ for (; data < lim; data += BGP_LABEL_BYTES)
+ {
+ memcpy(label, data, BGP_LABEL_BYTES);
+ llen += 3;
+ if (bgp_is_withdraw_label(label) || label_bos(label))
+ break;
+ }
+ if (!(bgp_is_withdraw_label(label) || label_bos(label)))
+ zlog_warn("%s: [Update:RCVD] invalid label - no bottom of stack",
+ peer->host);
+
+ return llen;
+}
+
+int
+bgp_nlri_parse_label (struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet)
+{
+ u_char *pnt;
+ u_char *lim;
+ struct prefix p;
+ int psize = 0;
+ int prefixlen;
+ afi_t afi;
+ safi_t safi;
+ int addpath_encoded;
+ u_int32_t addpath_id;
+ u_char label[3];
+ u_char llen;
+
+ /* Check peer status. */
+ if (peer->status != Established)
+ return 0;
+
+ pnt = packet->nlri;
+ lim = pnt + packet->length;
+ afi = packet->afi;
+ safi = packet->safi;
+ addpath_id = 0;
+
+ addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
+ CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+
+ for (; pnt < lim; pnt += psize)
+ {
+ /* Clear prefix structure. */
+ memset (&p, 0, sizeof (struct prefix));
+ llen = 0;
+
+ if (addpath_encoded)
+ {
+
+ /* When packet overflow occurs return immediately. */
+ if (pnt + BGP_ADDPATH_ID_LEN > lim)
+ return -1;
+
+ addpath_id = ntohl(*((uint32_t*) pnt));
+ pnt += BGP_ADDPATH_ID_LEN;
+ }
+
+ /* Fetch prefix length. */
+ prefixlen = *pnt++;
+ p.family = afi2family (packet->afi);
+ psize = PSIZE (prefixlen);
+
+ /* sanity check against packet data */
+ if ((pnt + psize) > lim)
+ {
+ zlog_err ("%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)",
+ peer->host,
+ prefixlen, (uint)(lim-pnt));
+ return -1;
+ }
+
+ /* Fill in the labels */
+ llen = bgp_nlri_get_labels(peer, pnt, psize, label);
+ // zlog_debug("rcvd label [%x/%x/%x], llen=%d\n", label[0], label[1], label[2], llen);
+ p.prefixlen -= BSIZE(llen);
+
+ /* There needs to be at least one label */
+ if (prefixlen < 24)
+ {
+ zlog_err ("%s [Error] Update packet error"
+ " (wrong label length %d)",
+ peer->host, prefixlen);
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+ return -1;
+ }
+
+ if ((afi == AFI_IP && p.prefixlen > 32)
+ || (afi == AFI_IP6 && p.prefixlen > 128))
+ return -1;
+
+ /* Fetch prefix from NLRI packet */
+ memcpy (&p.u.prefix, pnt + llen, psize - llen);
+
+ /* Check address. */
+ if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+ {
+ if (IN_CLASSD (ntohl (p.u.prefix4.s_addr)))
+ {
+ /* From RFC4271 Section 6.3:
+ *
+ * If a prefix in the NLRI field is semantically incorrect
+ * (e.g., an unexpected multicast IP address), an error SHOULD
+ * be logged locally, and the prefix SHOULD be ignored.
+ */
+ zlog_err ("%s: IPv4 labeled-unicast NLRI is multicast address %s, ignoring",
+ peer->host, inet_ntoa (p.u.prefix4));
+ continue;
+ }
+ }
+
+ /* Check address. */
+ if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+ {
+ if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+ {
+ char buf[BUFSIZ];
+
+ zlog_err ("%s: IPv6 labeled-unicast NLRI is link-local address %s, ignoring",
+ peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+ continue;
+ }
+
+ if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6))
+ {
+ char buf[BUFSIZ];
+
+ zlog_err ("%s: IPv6 unicast NLRI is multicast address %s, ignoring",
+ peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+ continue;
+ }
+ }
+
+ if (attr)
+ {
+ bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, 0, NULL);
+ }
+ else
+ {
+ bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, NULL);
+ }
+ }
+
+ /* Packet length consistency check. */
+ if (pnt != lim)
+ {
+ zlog_err ("%s [Error] Update packet error / L-U (%zu data remaining after parsing)",
+ peer->host, lim - pnt);
+ return -1;
+ }
+
+ return 0;
+}