diff options
author | Don Slice <dslice@cumulusnetworks.com> | 2017-03-09 15:54:20 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-04-06 16:32:07 +0200 |
commit | cd1964ff38bdbd2b5d36d0a0d89890e9d1bb2a50 (patch) | |
tree | 204d8be9bf9c213e4a895b1d335fafc8cc4c7d3f | |
parent | bgpd: labeled unicast config (diff) | |
download | frr-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>
-rw-r--r-- | bgpd/Makefile.am | 5 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 14 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_label.c | 318 | ||||
-rw-r--r-- | bgpd/bgp_label.h | 124 | ||||
-rw-r--r-- | bgpd/bgp_main.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_nht.c | 18 | ||||
-rw-r--r-- | bgpd/bgp_open.c | 8 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 5 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 137 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 13 | ||||
-rw-r--r-- | bgpd/bgp_table.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_updgrp_adv.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_updgrp_packet.c | 15 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 156 | ||||
-rw-r--r-- | bgpd/bgp_zebra.h | 6 | ||||
-rw-r--r-- | bgpd/bgpd.c | 8 | ||||
-rw-r--r-- | bgpd/bgpd.h | 13 | ||||
-rw-r--r-- | lib/prefix.h | 2 | ||||
-rw-r--r-- | lib/stream.c | 25 | ||||
-rw-r--r-- | lib/stream.h | 3 |
21 files changed, 819 insertions, 60 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index b6ed9a4d6..4ea045552 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -81,7 +81,7 @@ libbgp_a_SOURCES = \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ - bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c + bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c noinst_HEADERS = \ bgp_memory.h \ @@ -92,7 +92,8 @@ noinst_HEADERS = \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h + $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \ + bgp_vpn.h bgp_label.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 1fccd25c8..2c6bb5de0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2748,6 +2748,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, { case SAFI_UNICAST: case SAFI_MULTICAST: + case SAFI_LABELED_UNICAST: bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr); stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); @@ -2772,6 +2773,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, { case SAFI_UNICAST: case SAFI_MULTICAST: + case SAFI_LABELED_UNICAST: { struct attr_extra *attre = attr->extra; @@ -2875,6 +2877,11 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, { bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr); } + else if (safi == SAFI_LABELED_UNICAST) + { + /* Prefix write with label. */ + stream_put_labeled_prefix(s, p, tag); + } else stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id); } @@ -3112,7 +3119,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); } - else if (safi == SAFI_UNICAST && peer_cap_enhe(from)) + else if (peer_cap_enhe(from)) { /* * Likely this is the case when an IPv4 prefix was received with @@ -3439,6 +3446,11 @@ bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, u_char *tag, int addpath_encode, u_int32_t addpath_tx_id, struct attr *attr) { + u_char wlabel[3] = {0x80, 0x00, 0x00}; + + if (safi == SAFI_LABELED_UNICAST) + tag = wlabel; + return bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag, addpath_encode, addpath_tx_id, attr); } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 2bbdca595..b17888482 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1142,9 +1142,11 @@ bgp_stop (struct peer *peer) /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; + peer->pcount[AFI_IP][SAFI_LABELED_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; + peer->pcount[AFI_IP6][SAFI_LABELED_UNICAST] = 0; #endif /* 0 */ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && 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; +} diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h new file mode 100644 index 000000000..a7e7d5c47 --- /dev/null +++ b/bgpd/bgp_label.h @@ -0,0 +1,124 @@ +/* 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. + */ + +#ifndef _BGP_LABEL_H +#define _BGP_LABEL_H + +#define BGP_LABEL_BYTES 3 +#define BGP_LABEL_BITS 24 +#define BGP_WITHDRAW_LABEL 0x800000 + +struct bgp_node; +struct bgp_info; +struct peer; + +extern void bgp_reg_dereg_for_label (struct bgp_node *rn, int reg); +extern int bgp_parse_fec_update(void); +extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri, + struct peer *to, afi_t afi, safi_t safi); + +extern int bgp_nlri_parse_label (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet); + +static inline int +bgp_labeled_safi (safi_t safi) +{ + if ((safi == SAFI_LABELED_UNICAST) || (safi == SAFI_MPLS_VPN)) + return 1; + return 0; +} + +static inline int +bgp_is_withdraw_label (u_char *pkt) +{ + if ((pkt[0] == 0x80) && (pkt[1] == 0x00) && (pkt[2] == 0x00)) + return 1; + return 0; +} + +static inline u_char * +bgp_encode_withdraw_label (u_char *pkt) +{ + *pkt++ = 0x80; *pkt++ = 0x00; *pkt++ = 0x00; + return pkt; +} + +static inline int +bgp_is_valid_label (u_char *t) +{ + if (!t) + return 0; + return (t[2] & 0x02); +} + +static inline void +bgp_set_valid_label (u_char *t) +{ + if (t) + t[2] |= 0x02; +} + +static inline void +bgp_unset_valid_label (u_char *t) +{ + if (t) + t[2] &= ~0x02; +} + +static inline void +bgp_register_for_label (struct bgp_node *rn) +{ + bgp_reg_dereg_for_label (rn, 1); +} + +static inline void +bgp_unregister_for_label (struct bgp_node *rn) +{ + bgp_reg_dereg_for_label (rn, 0); +} + +/* Label stream to value */ +static inline u_int32_t +label_pton (u_char t[]) +{ + return ((((unsigned int) t[0]) << 12) | (((unsigned int) t[1]) << 4) | + ((unsigned int) ((t[2] & 0xF0) >> 4))); +} + +/* Encode label values */ +static inline void +label_ntop (u_int32_t l, int bos, u_char t[]) +{ + t[0] = ((l & 0x000FF000) >> 12); + t[1] = ((l & 0x00000FF0) >> 4); + t[2] = ((l & 0x0000000F) << 4); + if (bos) + t[2] |= 0x01; +} + +/* Return BOS value of label stream */ +static inline u_char +label_bos (u_char t[]) +{ + return (t[2] & 0x01); +}; + +#endif /* _BGP_LABEL_H */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 423c9453e..152d4a7ac 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -235,6 +235,8 @@ bgp_exit (int status) stream_free (bgp_nexthop_buf); if (bgp_ifindices_buf) stream_free (bgp_ifindices_buf); + if (bgp_label_buf) + stream_free (bgp_label_buf); /* reverse bgp_master_init */ if (bm->master) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index b0362b553..1e8dc5d97 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -404,8 +404,9 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) { char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof (buf)); - zlog_debug("%d: NH update for %s - metric %d (cur %d) #nhops %d (cur %d)", - vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num); + zlog_debug("%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", + vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num, + bnc->flags); } if (metric != bnc->metric) @@ -678,6 +679,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) struct bgp *bgp = bnc->bgp; int afi; struct peer *peer = (struct peer *)bnc->nht_info; + struct bgp_table *table; + safi_t safi; if (BGP_DEBUG(nht, NHT)) { @@ -695,7 +698,10 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) continue; rn = path->net; + assert (rn && bgp_node_table (rn)); afi = family2afi(rn->p.family); + table = bgp_node_table (rn); + safi = table->safi; /* Path becomes valid/invalid depending on whether the nexthop * reachable/unreachable. @@ -705,15 +711,13 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) { if (CHECK_FLAG (path->flags, BGP_INFO_VALID)) { - bgp_aggregate_decrement (bgp, &rn->p, path, - afi, SAFI_UNICAST); + bgp_aggregate_decrement (bgp, &rn->p, path, afi, safi); bgp_info_unset_flag (rn, path, BGP_INFO_VALID); } else { bgp_info_set_flag (rn, path, BGP_INFO_VALID); - bgp_aggregate_increment (bgp, &rn->p, path, - afi, SAFI_UNICAST); + bgp_aggregate_increment (bgp, &rn->p, path, afi, safi); } } @@ -727,7 +731,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); - bgp_process(bgp, rn, afi, SAFI_UNICAST); + bgp_process(bgp, rn, afi, safi); } if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 51079f31e..83fc3fe97 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -108,6 +108,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case SAFI_MULTICAST: json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "multicast"); break; + case SAFI_LABELED_UNICAST: + json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "labeled-unicast"); + break; case SAFI_MPLS_VPN: json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "MPLS-labeled VPN"); break; @@ -148,6 +151,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case SAFI_MULTICAST: vty_out (vty, "SAFI Multicast"); break; + case SAFI_LABELED_UNICAST: + vty_out (vty, "SAFI Labeled-unicast"); + break; case SAFI_MPLS_VPN: vty_out (vty, "SAFI MPLS-labeled VPN"); break; @@ -1143,10 +1149,12 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] + && ! peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP][SAFI_ENCAP] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + && ! peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP] && ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 853fcc869..f7a78caf9 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -55,6 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_label.h" /* Set up BGP packet marker and packet type. */ int @@ -1153,8 +1154,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) { peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; + peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP][SAFI_LABELED_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; + peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]; } /* When collision is detected and this peer is closed. Retrun @@ -1342,6 +1345,8 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, i case SAFI_UNICAST: case SAFI_MULTICAST: return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet); + case SAFI_LABELED_UNICAST: + return bgp_nlri_parse_label (peer, attr, packet); case SAFI_MPLS_VPN: return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet); case SAFI_ENCAP: diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 432a566c1..77154b0f3 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "workqueue.h" #include "queue.h" +#include "mpls.h" #include "memory.h" #include "lib/json.h" @@ -62,6 +63,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_label.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -1187,7 +1189,8 @@ subgroup_announce_reset_nhop (u_char family, struct attr *attr) } int -subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, +subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri, + struct update_subgroup *subgrp, struct prefix *p, struct attr *attr) { struct bgp_filter *filter; @@ -1261,6 +1264,21 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, return 0; } + /* If it's labeled safi, make sure the route has a valid label. */ + if (bgp_labeled_safi(safi)) + { + u_char *tag = bgp_adv_label(rn, ri, peer, afi, safi); + if (!bgp_is_valid_label(tag)) + { + if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s/%d is filtered - no label (%p)", + subgrp->update_group->id, subgrp->id, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, tag); + return 0; + } + } + /* Do not send back route to sender. */ if (onlypeer && from == onlypeer) { @@ -1804,7 +1822,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, /* Announcement to the subgroup. If the route is filtered withdraw it. */ if (selected) { - if (subgroup_announce_check(selected, subgrp, p, &attr)) + if (subgroup_announce_check(rn, selected, subgrp, p, &attr)) bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected); else bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id); @@ -1890,6 +1908,7 @@ bgp_process_main (struct work_queue *wq, void *data) struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; + int label_valid; /* Is it end of initial update? (after startup) */ if (!rn) @@ -1914,7 +1933,24 @@ bgp_process_main (struct work_queue *wq, void *data) old_select = old_and_new.old; new_select = old_and_new.new; - /* Nothing to do. */ + /* Do we need to allocate or free labels? + * Right now, since we only deal with per-prefix labels, it is not necessary + * to do this upon changes to best path. + */ + bgp_table_lock (bgp_node_table (rn)); + if (bgp_labeled_safi (safi)) + { + label_valid = bgp_is_valid_label (rn->local_label); + if (!old_select && new_select && !label_valid) + bgp_register_for_label (rn); + else if (old_select && !new_select) + bgp_unregister_for_label (rn); + } + + /* If best route remains the same and this is not due to user-initiated + * clear, see exactly what needs to be done. + */ + if (old_select && old_select == new_select && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && @@ -1926,10 +1962,26 @@ bgp_process_main (struct work_queue *wq, void *data) vnc_import_bgp_add_route(bgp, p, old_select); vnc_import_bgp_exterior_add_route(bgp, p, old_select); #endif - bgp_zebra_announce (p, old_select, bgp, afi, safi); + if (bgp_fibupd_safi(safi) && + !bgp->name && + !bgp_option_check (BGP_OPT_NO_FIB) && + new_select->type == ZEBRA_ROUTE_BGP && + new_select->sub_type == BGP_ROUTE_NORMAL) + bgp_zebra_announce (rn, p, old_select, bgp, afi, safi); } UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags (rn); + + /* If there is a change of interest to peers, reannounce the route. */ + if (CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED) || + CHECK_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED)) + { + group_announce_route(bgp, afi, safi, rn, new_select); + + UNSET_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED); + UNSET_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED); + } + UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1978,7 +2030,7 @@ bgp_process_main (struct work_queue *wq, void *data) group_announce_route(bgp, afi, safi, rn, new_select); /* FIB update. */ - if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && + if (bgp_fibupd_safi(safi) && (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) && !bgp_option_check (BGP_OPT_NO_FIB)) { @@ -1986,7 +2038,7 @@ bgp_process_main (struct work_queue *wq, void *data) && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_AGGREGATE)) - bgp_zebra_announce (p, new_select, bgp, afi, safi); + bgp_zebra_announce (rn, p, new_select, bgp, afi, safi); else { /* Withdraw the route from the kernel. */ @@ -2406,6 +2458,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct bgp_info *new; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; + char label_buf[20]; int connected = 0; int do_loop_check = 1; #if ENABLE_BGP_VNC @@ -2417,6 +2470,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); + label_buf[0] = '\0'; + if (bgp_labeled_safi(safi)) + sprintf (label_buf, "label %u", label_pton(tag)); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -2516,6 +2572,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new) + && (!bgp_labeled_safi(safi) || + memcmp ((bgp_info_extra_get (ri))->tag, tag, 3) == 0) && (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id, evpn==NULL?NULL:&evpn->gw_ip))) { @@ -2524,9 +2582,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s", peer->host, + zlog_debug ("%s rcvd %s %s", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { @@ -2544,10 +2602,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd %s...duplicate ignored", + zlog_debug ("%s rcvd %s %s...duplicate ignored", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? - 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf))); + 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); } /* graceful restart STALE flag unset. */ @@ -2568,18 +2626,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s, flapped quicker than processing", + zlog_debug ("%s rcvd %s %s, flapped quicker than processing", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); bgp_info_restore (rn, ri); } /* Received Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s rcvd %s", peer->host, + zlog_debug ("%s rcvd %s %s", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) @@ -2637,7 +2695,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, ri->attr = attr_new; /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) + if (bgp_labeled_safi(safi)) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); #if ENABLE_BGP_VNC @@ -2678,8 +2736,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } } - /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) + /* Nexthop reachability check - for unicast and labeled-unicast.. */ + if ((afi == AFI_IP || afi == AFI_IP6) && + (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -2759,16 +2818,16 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd %s", peer->host, + zlog_debug ("%s rcvd %s%s ", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf))); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf); } /* Make new BGP info. */ new = info_make(type, sub_type, 0, peer, attr_new, rn); /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) + if (bgp_labeled_safi(safi) || safi == SAFI_EVPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); /* Update Overlay Index */ @@ -2778,7 +2837,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, evpn==NULL?NULL:&evpn->gw_ip); } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) + if ((afi == AFI_IP || afi == AFI_IP6) && + (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -2873,10 +2933,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s", + zlog_debug ("%s rcvd UPDATE about %s %s -- DENIED due to: %s", peer->host, bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, - addpath_id, pfx_buf, sizeof (pfx_buf)), reason); + addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf, reason); } if (ri) @@ -3818,9 +3878,11 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, #endif /* Nexthop reachability check. */ - if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) + if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) && + safi == SAFI_UNICAST) { - if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0)) + if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0) && + safi == SAFI_UNICAST) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { @@ -5557,6 +5619,8 @@ bgp_aggregate_unset (struct vty *vty, const char *prefix_str, aggregate = rn->info; if (aggregate->safi & SAFI_UNICAST) bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (aggregate->safi & SAFI_LABELED_UNICAST) + bgp_aggregate_delete (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate); if (aggregate->safi & SAFI_MULTICAST) bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); @@ -5615,6 +5679,8 @@ bgp_aggregate_set (struct vty *vty, const char *prefix_str, /* Aggregate address insert into BGP routing table. */ if (safi & SAFI_UNICAST) bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (safi & SAFI_LABELED_UNICAST) + bgp_aggregate_add (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate); if (safi & SAFI_MULTICAST) bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); @@ -7439,6 +7505,15 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo, json_path); + if (bgp_labeled_safi(safi) && binfo->extra) + { + uint32_t label = label_pton(binfo->extra->tag); + if (json_paths) + json_object_int_add(json_path, "remote-label", label); + else + vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE); + } + /* Line 8 display Addpath IDs */ if (binfo->addpath_rx_id || binfo->addpath_tx_id) { @@ -7932,6 +8007,18 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "", buf2, p->prefixlen, VTY_NEWLINE); + + if (bgp_labeled_safi(safi)) + { + vty_out(vty, "Local label: "); + if (!bgp_is_valid_label(rn->local_label)) + vty_out(vty, "not allocated%s", VTY_NEWLINE); + else + { + uint32_t label = label_pton(rn->local_label); + vty_out(vty, "%d%s", label, VTY_NEWLINE); + } + } } for (ri = rn->info; ri; ri = ri->next) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e75978d00..69b8ea8a5 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -150,6 +150,7 @@ struct bgp_info #define BGP_INFO_COUNTED (1 << 10) #define BGP_INFO_MULTIPATH (1 << 11) #define BGP_INFO_MULTIPATH_CHG (1 << 12) +#define BGP_INFO_RIB_ATTR_CHG (1 << 13) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ u_char type; @@ -273,6 +274,16 @@ bgp_bump_version (struct bgp_node *node) node->version = bgp_table_next_version(bgp_node_table(node)); } +static inline int +bgp_fibupd_safi (safi_t safi) +{ + if (safi == SAFI_UNICAST || + safi == SAFI_MULTICAST || + safi == SAFI_LABELED_UNICAST) + return 1; + return 0; +} + /* Prototypes. */ extern void bgp_process_queue_init (void); extern void bgp_route_init (void); @@ -370,7 +381,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, struct bgp_node *rn, u_int32_t addpath_tx_id); -extern int subgroup_announce_check(struct bgp_info *ri, +extern int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri, struct update_subgroup *subgrp, struct prefix *p, struct attr *attr); diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 3c96dac61..2b874f66a 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -56,10 +56,13 @@ struct bgp_node struct bgp_node *prn; + u_char local_label[3]; + uint64_t version; u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) #define BGP_NODE_USER_CLEAR (1 << 1) +#define BGP_NODE_LABEL_CHANGED (1 << 2) }; /* diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index efb2046e1..ac5f77474 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -618,7 +618,7 @@ subgroup_announce_table (struct update_subgroup *subgrp, if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) || (addpath_capable && bgp_addpath_tx_path(peer, afi, safi, ri))) { - if (subgroup_announce_check (ri, subgrp, &rn->p, &attr)) + if (subgroup_announce_check (rn, ri, subgrp, &rn->p, &attr)) bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri); else bgp_adj_out_unset_subgroup (rn, subgrp, 1, ri->addpath_tx_id); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 57e5c0702..135cdadb2 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -43,6 +43,7 @@ #include "workqueue.h" #include "hash.h" #include "queue.h" +#include "mpls.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_debug.h" @@ -54,6 +55,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_label.h" /******************** * PRIVATE FUNCTIONS @@ -653,6 +655,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) int addpath_encode = 0; u_int32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; + char label_buf[20]; if (!subgrp) return NULL; @@ -660,7 +663,6 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp))) return NULL; - peer = SUBGRP_PEER (subgrp); afi = SUBGRP_AFI (subgrp); safi = SUBGRP_SAFI (subgrp); @@ -668,6 +670,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) stream_reset (s); snlri = subgrp->scratch; stream_reset (snlri); + label_buf[0] = '\0'; bpacket_attr_vec_arr_reset (&vecarr); @@ -760,8 +763,9 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; - if (binfo && binfo->extra) - tag = binfo->extra->tag; + tag = bgp_adv_label(rn, binfo, peer, afi, safi); + if (bgp_labeled_safi(safi)) + sprintf (label_buf, "label %u", label_pton(tag)); if (stream_empty (snlri)) mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi, @@ -797,11 +801,12 @@ subgroup_update_packet (struct update_subgroup *subgrp) send_attr_printed = 1; } - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s %s", subgrp->update_group->id, subgrp->id, bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode, addpath_tx_id, - pfx_buf, sizeof (pfx_buf))); + pfx_buf, sizeof (pfx_buf)), + label_buf); } /* Synchnorize attribute. */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 72bd081a7..1ded613f6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */ #include "lib/json.h" #include "lib/bfd.h" #include "filter.h" +#include "mpls.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -46,6 +47,7 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_bfd.h" +#include "bgpd/bgp_label.h" #if ENABLE_BGP_VNC # include "bgpd/rfapi/rfapi_backend.h" # include "bgpd/rfapi/vnc_export_bgp.h" @@ -57,6 +59,7 @@ struct zclient *zclient = NULL; /* Growable buffer for nexthops sent to zebra */ struct stream *bgp_nexthop_buf = NULL; struct stream *bgp_ifindices_buf = NULL; +struct stream *bgp_label_buf = NULL; /* These array buffers are used in making a copy of the attributes for route-map apply. Arrays are being used here to minimize mallocs and @@ -178,6 +181,14 @@ bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp, } } +static int +bgp_read_fec_update (int command, struct zclient *zclient, + zebra_size_t length) +{ + bgp_parse_fec_update(); + return 0; +} + static void bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp) { @@ -1204,8 +1215,8 @@ bgp_table_map_apply (struct route_map *map, struct prefix *p, } void -bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, - afi_t afi, safi_t safi) +bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info, + struct bgp *bgp, afi_t afi, safi_t safi) { u_int32_t flags; u_char distance; @@ -1216,6 +1227,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, struct bgp_info local_info; struct bgp_info *info_cp = &local_info; route_tag_t tag; + u_int32_t label; /* Don't try to install if we're not connected to Zebra or Zebra doesn't * know of this instance. @@ -1271,7 +1283,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if ((oldsize = stream_get_size (bgp_nexthop_buf)) < (sizeof (struct in_addr *) * nhcount)) { - newsize = (sizeof (struct in_addr *) * nhcount); + newsize = sizeof (struct in_addr *) * nhcount; newsize = stream_resize (bgp_nexthop_buf, newsize); if (newsize == oldsize) { @@ -1282,6 +1294,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, stream_reset (bgp_nexthop_buf); nexthop = NULL; + /* For labeled unicast, each nexthop has a label too. Resize label + * buffer, if required. + */ + if (safi == SAFI_LABELED_UNICAST) + { + if ((oldsize = stream_get_size (bgp_label_buf)) < + (sizeof (unsigned int) * nhcount)) + { + newsize = (sizeof (unsigned int) * nhcount); + newsize = stream_resize (bgp_label_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize label buffer"); + return; + } + } + stream_reset (bgp_label_buf); + } + /* Metric is currently based on the best-path only. */ metric = info->attr->med; @@ -1311,6 +1342,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, { stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); valid_nh_count++; + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(info->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } } for (mpinfo = bgp_info_mpath_first (info); mpinfo; @@ -1336,6 +1372,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, continue; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(mpinfo->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } valid_nh_count++; } @@ -1344,8 +1385,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); /* Note that this currently only applies to Null0 routes for aggregates. * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a special @@ -1358,6 +1401,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.nexthop_num = valid_nh_count; api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf); + if (safi == SAFI_LABELED_UNICAST) + { + api.label_num = valid_nh_count; + api.label = (unsigned int *)STREAM_DATA (bgp_label_buf); + } + else + { + api.label_num = 0; + api.label = NULL; + } api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; @@ -1379,14 +1432,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (bgp_debug_zebra(p)) { int i; + char label_buf[20]; zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI " count %d", (valid_nh_count ? "add":"delete"), bgp->vrf_id, inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag, api.nexthop_num); for (i = 0; i < api.nexthop_num; i++) - zlog_debug(" IPv4 [nexthop %d] %s", i+1, - inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1]))); + { + label_buf[0] = '\0'; + if (safi == SAFI_LABELED_UNICAST) + sprintf(label_buf, "label %u", api.label[i]); + zlog_debug(" nhop [%d]: %s %s", + i+1, + inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])), + label_buf); + } } zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE, @@ -1431,6 +1492,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, } stream_reset (bgp_ifindices_buf); + /* For labeled unicast, each nexthop has a label too. Resize label + * buffer, if required. + */ + if (safi == SAFI_LABELED_UNICAST) + { + if ((oldsize = stream_get_size (bgp_label_buf)) < + (sizeof (unsigned int) * nhcount)) + { + newsize = (sizeof (unsigned int) * nhcount); + newsize = stream_resize (bgp_label_buf, newsize); + if (newsize == oldsize) + { + zlog_err ("can't resize label buffer"); + return; + } + } + stream_reset (bgp_label_buf); + } + ifindex = 0; nexthop = NULL; @@ -1476,6 +1556,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, } stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(info->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } valid_nh_count++; } @@ -1518,6 +1603,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); + if (safi == SAFI_LABELED_UNICAST) + { + label = label_pton(mpinfo->extra->tag); + stream_put (bgp_label_buf, &label, sizeof (u_int32_t)); + } valid_nh_count++; } @@ -1527,8 +1617,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); /* Note that this currently only applies to Null0 routes for aggregates. * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a special @@ -1544,6 +1636,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = valid_nh_count; api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf); + if (safi == SAFI_LABELED_UNICAST) + { + api.label_num = valid_nh_count; + api.label = (unsigned int *)STREAM_DATA (bgp_label_buf); + } + else + { + api.label_num = 0; + api.label = NULL; + } SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; api.tag = 0; @@ -1566,13 +1668,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (bgp_debug_zebra(p)) { int i; + char label_buf[20]; zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI, valid_nh_count ? "add" : "delete", bgp->vrf_id, inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag); for (i = 0; i < api.nexthop_num; i++) - zlog_debug(" IPv6 [nexthop %d] %s", i+1, - inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1]))); + { + label_buf[0] = '\0'; + if (safi == SAFI_LABELED_UNICAST) + sprintf(label_buf, "label %u", api.label[i]); + zlog_debug(" nhop [%d]: %s if %s %s", + i+1, + inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])), + ifindex2ifname (api.ifindex[i], bgp->vrf_id), + label_buf); + } } if (valid_nh_count) @@ -1588,13 +1699,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, if (bgp_debug_zebra(p)) { int i; + char label_buf[20]; zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI, valid_nh_count ? "add" : "delete", bgp->vrf_id, inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag); for (i = 0; i < api.nexthop_num; i++) - zlog_debug(" IPv6 [nexthop %d] %s", i+1, - inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1]))); + { + label_buf[0] = '\0'; + if (safi == SAFI_LABELED_UNICAST) + sprintf(label_buf, "label %u", api.label[i]); + zlog_debug(" nhop [%d]: %s if %s %s", + i+1, + inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])), + ifindex2ifname (api.ifindex[i], bgp->vrf_id), + label_buf); + } } zapi_ipv6_route (valid_nh_count ? @@ -1626,7 +1746,7 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_announce (&rn->p, ri, bgp, afi, safi); + bgp_zebra_announce (rn, &rn->p, ri, bgp, afi, safi); } void @@ -1673,10 +1793,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); api.nexthop_num = 0; api.nexthop = NULL; + api.label_num = 0; + api.label = NULL; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; @@ -1712,11 +1836,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.type = ZEBRA_ROUTE_BGP; api.instance = 0; api.message = 0; - api.safi = safi; + api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG (api.message, ZAPI_MESSAGE_LABEL); api.nexthop_num = 0; api.nexthop = NULL; api.ifindex_num = 0; + api.label_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; api.tag = 0; @@ -2141,6 +2268,7 @@ bgp_zebra_init (struct thread_master *master) zclient->redistribute_route_ipv6_del = zebra_read_ipv6; zclient->nexthop_update = bgp_read_nexthop_update; zclient->import_check_update = bgp_read_import_check_update; + zclient->fec_update = bgp_read_fec_update; bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE); diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index d22a00e8f..bc4e36352 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -23,9 +23,11 @@ Boston, MA 02111-1307, USA. */ #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) #define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int)) +#define BGP_LABEL_BUF_SIZE (8 * sizeof (unsigned int)) extern struct stream *bgp_nexthop_buf; extern struct stream *bgp_ifindices_buf; +extern struct stream *bgp_label_buf; extern void bgp_zebra_init (struct thread_master *master); extern void bgp_zebra_destroy (void); @@ -34,8 +36,8 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, safi_t, int *); extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, int *); -extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, - afi_t, safi_t); +extern void bgp_zebra_announce (struct bgp_node *, struct prefix *, + struct bgp_info *, struct bgp *, afi_t, safi_t); extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t); extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0ed277b16..1c73fb940 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1636,6 +1636,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP], @@ -1644,6 +1646,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP], @@ -3608,10 +3612,12 @@ peer_active (struct peer *peer) return 0; if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] + || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] + || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP]) return 1; @@ -3624,10 +3630,12 @@ peer_active_nego (struct peer *peer) { if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP][SAFI_ENCAP] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) return 1; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index a72974bc1..e95d05922 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -76,6 +76,8 @@ enum bgp_af_index BGP_AF_IPV4_ENCAP, BGP_AF_IPV6_ENCAP, BGP_AF_L2VPN_EVPN, + BGP_AF_IPV4_LBL_UNICAST, + BGP_AF_IPV6_LBL_UNICAST, BGP_AF_MAX }; @@ -1394,6 +1396,9 @@ afindex (afi_t afi, safi_t safi) case SAFI_MULTICAST: return BGP_AF_IPV4_MULTICAST; break; + case SAFI_LABELED_UNICAST: + return BGP_AF_IPV4_LBL_UNICAST; + break; case SAFI_MPLS_VPN: return BGP_AF_IPV4_VPN; break; @@ -1414,7 +1419,10 @@ afindex (afi_t afi, safi_t safi) case SAFI_MULTICAST: return BGP_AF_IPV6_MULTICAST; break; - case SAFI_MPLS_VPN: + case SAFI_LABELED_UNICAST: + return BGP_AF_IPV6_LBL_UNICAST; + break; + case SAFI_MPLS_VPN: return BGP_AF_IPV6_VPN; break; case SAFI_ENCAP: @@ -1456,6 +1464,7 @@ peer_afi_active_nego (const struct peer *peer, afi_t afi) { if (peer->afc_nego[afi][SAFI_UNICAST] || peer->afc_nego[afi][SAFI_MULTICAST] + || peer->afc_nego[afi][SAFI_LABELED_UNICAST] || peer->afc_nego[afi][SAFI_MPLS_VPN] || peer->afc_nego[afi][SAFI_ENCAP]) return 1; @@ -1470,10 +1479,12 @@ peer_group_af_configured (struct peer_group *group) if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] + || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] + || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP]) return 1; diff --git a/lib/prefix.h b/lib/prefix.h index eb3ae3daf..786c2bf7e 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -244,6 +244,8 @@ union prefixconstptr /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) +#define BSIZE(a) ((a) * (8)) + /* Prefix's family member. */ #define PREFIX_FAMILY(p) ((p)->family) diff --git a/lib/stream.c b/lib/stream.c index 301ebc627..32dde1ca0 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -919,6 +919,31 @@ stream_put_prefix (struct stream *s, struct prefix *p) return stream_put_prefix_addpath (s, p, 0, 0); } +/* Put NLRI with label */ +int +stream_put_labeled_prefix (struct stream *s, struct prefix *p, u_char *label) +{ + size_t psize; + + STREAM_VERIFY_SANE(s); + + psize = PSIZE (p->prefixlen); + + if (STREAM_WRITEABLE (s) < (psize + 3)) + { + STREAM_BOUND_WARN (s, "put"); + return 0; + } + + stream_putc (s, (p->prefixlen + 24)); + stream_putc(s, label[0]); + stream_putc(s, label[1]); + stream_putc(s, label[2]); + memcpy (s->data + s->endp, &p->u.prefix, psize); + s->endp += psize; + + return (psize + 3); +} /* Read size from fd. */ int diff --git a/lib/stream.h b/lib/stream.h index 1e2bc89b3..b7bf31bf7 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -181,7 +181,8 @@ extern int stream_put_prefix_addpath (struct stream *, struct prefix *, int addpath_encode, u_int32_t addpath_tx_id); extern int stream_put_prefix (struct stream *, struct prefix *); - +extern int stream_put_labeled_prefix (struct stream *, struct prefix *, + u_char *); extern void stream_get (void *, struct stream *, size_t); extern void stream_get_from (void *, struct stream *, size_t, size_t); extern u_char stream_getc (struct stream *); |