assert (attr->extra);
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
- stream_putc (s, attre->mp_nexthop_len);
- stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
- if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+
+ if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ stream_putc (s, BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
+ stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
stream_put (s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN);
+ } else {
+ stream_putc (s, IPV6_MAX_BYTELEN);
+ stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
+ }
}
break;
case SAFI_MPLS_VPN:
cp = stream_get_endp (s);
if (p && !((afi == AFI_IP && safi == SAFI_UNICAST) &&
- !peer_cap_enhe(peer)))
+ !peer_cap_enhe(peer, afi, safi)))
{
size_t mpattrlen_pos = 0;
mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi,
- (peer_cap_enhe(peer) ? AFI_IP6 :
- AFI_MAX), /* get from NH */
- vecarr, attr);
+ (peer_cap_enhe(peer, afi, safi) ? AFI_IP6 :
+ AFI_MAX), /* get from NH */
+ vecarr, attr);
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag,
addpath_encode, addpath_tx_id, attr);
bgp_packet_mpattr_end(s, mpattrlen_pos);
send_as4_path = 1; /* we'll do this later, at the correct place */
/* Nexthop attribute. */
- if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer))
+ if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer, afi, safi))
{
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
{
stream_putc (s, 4);
stream_put_ipv4 (s, attr->nexthop.s_addr);
}
- else if (peer_cap_enhe(from))
+ else if (peer_cap_enhe(from, afi, safi))
{
/*
* Likely this is the case when an IPv4 prefix was received with
/* RFC 5549 specifies use of this capability only for IPv4 AFI, with
* the Nexthop AFI being IPv6. A future spec may introduce other
* possibilities, so we ignore other values with a log. Also, only
- * Unicast SAFI is currently supported (and expected).
+ * SAFI_UNICAST and SAFI_LABELED_UNICAST are currently supported (and expected).
*/
nh_afi = afi_iana2int (pkt_nh_afi);
- if (afi != AFI_IP || safi != SAFI_UNICAST || nh_afi != AFI_IP6)
+ if (afi != AFI_IP || nh_afi != AFI_IP6 || !(safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
{
zlog_warn ("%s Unexpected afi/safi/next-hop afi: %u/%u/%u "
"in Extended Next-hop capability, ignoring",
stream_putw (s, pkt_afi);
stream_putc (s, 0);
stream_putc (s, pkt_safi);
+
+ /* Extended nexthop capability - currently supporting RFC-5549 for
+ * Link-Local peering only
+ */
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
+ peer->su.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr) &&
+ afi == AFI_IP &&
+ (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
+ {
+ /* RFC 5549 Extended Next Hop Encoding */
+ SET_FLAG (peer->cap, PEER_CAP_ENHE_ADV);
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_ENHE_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_ENHE);
+ stream_putc (s, CAPABILITY_CODE_ENHE_LEN);
+
+ SET_FLAG (peer->af_cap[AFI_IP][safi], PEER_CAP_ENHE_AF_ADV);
+ stream_putw (s, pkt_afi);
+ stream_putw (s, pkt_safi);
+ stream_putw (s, afi_int2iana(AFI_IP6));
+
+ if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_RCV))
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_NEGO);
+ }
}
}
- /* Extended nexthop capability - currently supporting RFC-5549 for
- * Link-Local peering only
- */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
- peer->su.sa.sa_family == AF_INET6 &&
- IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
- {
- /* RFC 5549 Extended Next Hop Encoding */
- SET_FLAG (peer->cap, PEER_CAP_ENHE_ADV);
- stream_putc (s, BGP_OPEN_OPT_CAP);
- stream_putc (s, CAPABILITY_CODE_ENHE_LEN + 2);
- stream_putc (s, CAPABILITY_CODE_ENHE);
- stream_putc (s, CAPABILITY_CODE_ENHE_LEN);
- /* Currently supporting for SAFI_UNICAST only */
- SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_ADV);
- stream_putw (s, AFI_IP);
- stream_putw (s, SAFI_UNICAST);
- stream_putw (s, AFI_IP6);
-
- if (CHECK_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_RCV))
- SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO);
- }
-
/* Route refresh. */
SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
stream_putc (s, BGP_OPEN_OPT_CAP);
#define NEXTHOP_IS_V6 (\
(safi != SAFI_ENCAP && safi != SAFI_MPLS_VPN &&\
- (p->family == AF_INET6 || peer_cap_enhe(peer))) || \
+ (p->family == AF_INET6 || peer_cap_enhe(peer, AFI_IP6, safi))) || \
((safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN) &&\
attr->extra->mp_nexthop_len >= IPV6_MAX_BYTELEN))
if (!reflect ||
CHECK_FLAG (peer->af_flags[afi][safi],
PEER_FLAG_FORCE_NEXTHOP_SELF))
- subgroup_announce_reset_nhop ((peer_cap_enhe(peer) ?
+ subgroup_announce_reset_nhop ((peer_cap_enhe(peer, afi, safi) ?
AF_INET6 : p->family), attr);
}
else if (peer->sort == BGP_PEER_EBGP)
break;
}
if (!paf)
- subgroup_announce_reset_nhop ((peer_cap_enhe(peer) ? AF_INET6 : p->family), attr);
+ subgroup_announce_reset_nhop ((peer_cap_enhe(peer, afi, safi) ? AF_INET6 : p->family), attr);
}
/* If IPv6/MP and nexthop does not have any override and happens to
* be a link-local address, reset it so that we don't pass along the
* source's link-local IPv6 address to recipients who may not be on
* the same interface.
*/
- if (p->family == AF_INET6 || peer_cap_enhe(peer))
+ if (p->family == AF_INET6 || peer_cap_enhe(peer, afi, safi))
{
if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
subgroup_announce_reset_nhop (AF_INET6, attr);
if (paf->afi == AFI_IP || paf->afi == AFI_IP6)
{
nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen);
- if (peer_cap_enhe(peer))
+ if (peer_cap_enhe(peer, paf->afi, paf->safi))
nhafi = AFI_IP6;
if (paf->safi == SAFI_MPLS_VPN && /* if VPN && not global */
nhlen != BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
}
if ((afi == AFI_IP && safi == SAFI_UNICAST) &&
- !peer_cap_enhe(peer))
+ !peer_cap_enhe(peer, afi, safi))
stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id);
else
{
if (stream_empty (snlri))
mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi,
- (peer_cap_enhe(peer) ? AFI_IP6 :
- AFI_MAX), /* get from NH */
- &vecarr, adv->baa->attr);
+ (peer_cap_enhe(peer, afi, safi) ? AFI_IP6 :
+ AFI_MAX), /* get from NH */
+ &vecarr, adv->baa->attr);
bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd,
tag, addpath_encode, addpath_tx_id, adv->baa->attr);
first_time = 0;
if (afi == AFI_IP && safi == SAFI_UNICAST &&
- !peer_cap_enhe(peer))
+ !peer_cap_enhe(peer, afi, safi))
stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id);
else
{
if (!stream_empty (s))
{
if (afi == AFI_IP && safi == SAFI_UNICAST &&
- !peer_cap_enhe(peer))
+ !peer_cap_enhe(peer, afi, safi))
{
unfeasible_len
= stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
/* NLRI set. */
if (p.family == AF_INET && safi == SAFI_UNICAST &&
- !peer_cap_enhe(peer))
+ !peer_cap_enhe(peer, afi, safi))
stream_put_prefix_addpath (s, &p, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
/* Set size. */
/* Withdrawn Routes. */
if (p.family == AF_INET && safi == SAFI_UNICAST &&
- !peer_cap_enhe(peer))
+ !peer_cap_enhe(peer, afi, safi))
{
stream_put_prefix_addpath (s, &p, addpath_encode,
BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0;
}
-/*
- * Currently supporting RFC 5549 for AFI_IP/SAFI_UNICAST only.
- *
- * Note: When other RFC-5549 applicable SAFIs to be supported, that should
- * come as an argument to this routine.
- */
static inline int
-peer_cap_enhe (struct peer *peer)
+peer_cap_enhe (struct peer *peer, afi_t afi, safi_t safi)
{
- return (CHECK_FLAG(peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO));
+ return (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_NEGO));
}
/* Lookup VRF for BGP instance based on its type. */
"AS number\n"
"Summary <network>/<length>, e.g. 192.168.0.0/16\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ //VTY_DECLVAR_CONTEXT(interface, ifp);
//u_int32_t AS;
struct eigrp *eigrp;
"AS number\n"
"Summary <network>/<length>, e.g. 192.168.0.0/16\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ //VTY_DECLVAR_CONTEXT(interface, ifp);
//u_int32_t AS;
struct eigrp *eigrp;
snhlfe_del_all (zebra_slsp_t *slsp);
static char *
snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size);
-static void
+static int
mpls_processq_init (struct zebra_t *zebra);
if (!lsp_table)
return -1;
- /* See if route entry is selected; we really expect only 1 entry here. */
- if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
- return 0;
-
lsp_type = lsp_type_from_rib_type (rib->type);
added = changed = 0;
if (CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
return 0;
+ if (zebrad.lsp_process_q == NULL)
+ {
+ zlog_err ("%s: work_queue does not exist!", __func__);
+ return -1;
+ }
+
work_queue_add (zebrad.lsp_process_q, lsp);
SET_FLAG (lsp->flags, LSP_FLAG_SCHEDULED);
return 0;
/*
* Initialize work queue for processing changed LSPs.
*/
-static void
+static int
mpls_processq_init (struct zebra_t *zebra)
{
zebra->lsp_process_q = work_queue_new (zebra->master, "LSP processing");
if (!zebra->lsp_process_q)
{
zlog_err ("%s: could not initialise work queue!", __func__);
- return;
+ return -1;
}
zebra->lsp_process_q->spec.workfunc = &lsp_process;
zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
zebra->lsp_process_q->spec.max_retries = 0;
zebra->lsp_process_q->spec.hold = 10;
+
+ return 0;
}
*/
char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
- char *buf, int len)
+ char *buf, int len, int pretty)
{
+ char *buf_ptr = buf;
buf[0] = '\0';
- if (num_labels == 1)
- snprintf (buf, len, "%u", labels[0]);
- else if (num_labels == 2)
- snprintf (buf, len, "%u/%u", labels[0], labels[1]);
+
+ if (pretty) {
+ if (num_labels == 1) {
+ label2str(labels[0], buf, len);
+ } else if (num_labels == 2) {
+ label2str(labels[0], buf, len);
+ buf_ptr += strlen(buf);
+
+ snprintf (buf_ptr, len, "/");
+ buf_ptr++;
+
+ label2str(labels[1], buf_ptr, len);
+ }
+ } else {
+ if (num_labels == 1)
+ snprintf (buf, len, "%u", labels[0]);
+ else if (num_labels == 2)
+ snprintf (buf, len, "%u/%u", labels[0], labels[1]);
+ }
return buf;
}
void
zebra_mpls_init (void)
{
+ mpls_enabled = 0;
+
if (mpls_kernel_init () < 0)
{
zlog_warn ("Disabling MPLS support (no kernel support)");
return;
}
- mpls_enabled = 1;
- mpls_processq_init (&zebrad);
+ if (! mpls_processq_init (&zebrad))
+ mpls_enabled = 1;
}
*/
char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
- char *buf, int len);
+ char *buf, int len, int pretty);
/*
* Add/update global label block.
char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
- char *buf, int len)
+ char *buf, int len, int pretty)
{
return NULL;
}
/* Label information */
if (nexthop->nh_label && nexthop->nh_label->num_labels)
{
- vty_out (vty, " label %s",
+ vty_out (vty, ", label %s",
mpls_label2str (nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf, BUFSIZ));
+ nexthop->nh_label->label, buf, BUFSIZ, 1));
}
vty_out (vty, "%s", VTY_NEWLINE);
json_object *json_nexthops = NULL;
json_object *json_nexthop = NULL;
json_object *json_route = NULL;
+ json_object *json_labels = NULL;
if (json)
{
break;
}
+ if (nexthop->nh_label && nexthop->nh_label->num_labels)
+ {
+ json_labels = json_object_new_array();
+
+ for (int label_index = 0; label_index < nexthop->nh_label->num_labels; label_index++)
+ json_object_array_add(json_labels, json_object_new_int(nexthop->nh_label->label[label_index]));
+
+ json_object_object_add(json_nexthop, "labels", json_labels);
+ }
+
json_object_array_add(json_nexthops, json_nexthop);
}
/* Label information */
if (nexthop->nh_label && nexthop->nh_label->num_labels)
{
- vty_out (vty, " label %s",
+ vty_out (vty, ", label %s",
mpls_label2str (nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf, BUFSIZ));
+ nexthop->nh_label->label, buf, BUFSIZ, 1));
}
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
if (si->snh_label.num_labels)
vty_out (vty, " label %s",
mpls_label2str (si->snh_label.num_labels,
- si->snh_label.label, buf, sizeof buf));
+ si->snh_label.label, buf, sizeof buf, 0));
vty_out (vty, "%s", VTY_NEWLINE);
if (si->snh_label.num_labels)
vty_out (vty, " label %s",
mpls_label2str (si->snh_label.num_labels,
- si->snh_label.label, buf, sizeof buf));
+ si->snh_label.label, buf, sizeof buf, 0));
vty_out (vty, "%s", VTY_NEWLINE);
return 0;
}
-#define ZEBRA_MIN_FEC_LENGTH 9
+#define ZEBRA_MIN_FEC_LENGTH 5
/* FEC register */
static int