Merge branch 'master' into EIGRP

This commit is contained in:
Donald Sharp 2017-05-02 11:38:06 -04:00 committed by GitHub
commit b46be72b4a
81 changed files with 6415 additions and 1157 deletions

View File

@ -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@

View File

@ -78,7 +78,8 @@ static const struct message attr_str [] =
#if ENABLE_BGP_VNC
{ BGP_ATTR_VNC, "VNC" },
#endif
{ BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
{ BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" },
{ BGP_ATTR_LABEL_INDEX, "LABEL_INDEX" }
};
static const int attr_str_max = array_size(attr_str);
@ -676,6 +677,7 @@ attrhash_key_make (void *p)
MIX(extra->mp_nexthop_global_in.s_addr);
MIX(extra->originator_id.s_addr);
MIX(extra->tag);
MIX(extra->label_index);
}
if (attr->aspath)
@ -730,6 +732,7 @@ attrhash_cmp (const void *p1, const void *p2)
&& ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
&& ae1->weight == ae2->weight
&& ae1->tag == ae2->tag
&& ae1->label_index == ae2->label_index
&& ae1->mp_nexthop_len == ae2->mp_nexthop_len
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
@ -1287,6 +1290,7 @@ const u_int8_t attr_flags_values [] = {
[BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_LABEL_INDEX] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@ -2274,6 +2278,52 @@ bgp_attr_encap(
return 0;
}
/* Label index attribute */
static bgp_attr_parse_ret_t
bgp_attr_label_index (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update)
{
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
u_int32_t label_index;
/* Length check. */
if (length != 8)
{
zlog_err ("Bad label index length %d", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
/* First u32 is currently unused - reserved and flags (undefined) */
stream_getl (peer->ibuf);
/* Fetch the label index and see if it is valid. */
label_index = stream_getl (peer->ibuf);
if (label_index == BGP_INVALID_LABEL_INDEX)
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
/* Store label index; subsequently, we'll check on address-family */
(bgp_attr_extra_get (attr))->label_index = label_index;
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX);
/*
* Ignore the Label index attribute unless received for labeled-unicast
* SAFI. We reset the flag, though it is probably unnecesary.
*/
if (!mp_update->length || mp_update->safi != SAFI_LABELED_UNICAST)
{
attr->extra->label_index = BGP_INVALID_LABEL_INDEX;
attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LABEL_INDEX);
}
return BGP_ATTR_PARSE_PROCEED;
}
/* BGP unknown attribute treatment. */
static bgp_attr_parse_ret_t
bgp_attr_unknown (struct bgp_attr_parser_args *args)
@ -2572,6 +2622,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_ENCAP:
ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
break;
case BGP_ATTR_LABEL_INDEX:
ret = bgp_attr_label_index (&attr_args, mp_update);
break;
default:
ret = bgp_attr_unknown (&attr_args);
break;
@ -2740,6 +2793,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
if (nh_afi == AFI_MAX)
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len);
/* Nexthop */
switch (nh_afi)
{
@ -2748,6 +2802,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 +2827,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 +2931,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 +3173,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
@ -3348,6 +3409,23 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
}
}
/* Label index attribute. */
if (safi == SAFI_LABELED_UNICAST)
{
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
{
u_int32_t label_index;
assert (attr->extra);
label_index = attr->extra->label_index;
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_LABEL_INDEX);
stream_putc (s, 8);
stream_putl (s, 0);
stream_putl (s, label_index);
}
}
if ( send_as4_path )
{
/* If the peer is NOT As4 capable, AND */
@ -3439,6 +3517,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);
}
@ -3626,6 +3709,17 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
}
/* Label index */
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
{
assert (attr->extra);
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_LABEL_INDEX);
stream_putc (s, 8);
stream_putl (s, 0);
stream_putl (s, attr->extra->label_index);
}
/* Return total size of attribute. */
len = stream_get_endp (s) - cp - 2;
stream_putw_at (s, cp, len);

View File

@ -134,6 +134,9 @@ struct attr_extra
/* route tag */
route_tag_t tag;
/* Label index */
u_int32_t label_index;
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
@ -160,7 +163,7 @@ struct attr
unsigned long refcnt;
/* Flag of attribute is set or not. */
u_int32_t flag;
uint64_t flag;
/* Apart from in6_addr, the remaining static attributes */
struct in_addr nexthop;
@ -201,7 +204,7 @@ struct transit
u_char *val;
};
#define ATTR_FLAG_BIT(X) (1 << ((X) - 1))
#define ATTR_FLAG_BIT(X) (1ULL << ((X) - 1))
#define BGP_CLUSTER_LIST_LENGTH(attr) \
(((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ? \

View File

@ -450,6 +450,10 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
aspath_print (attr->aspath));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))
snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u",
attr->extra->label_index);
if (strlen (buf) > 1)
return 1;
else

View File

@ -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) &&

338
bgpd/bgp_label.c Normal file
View File

@ -0,0 +1,338 @@
/* 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, struct bgp_info *ri,
int reg)
{
struct stream *s;
struct prefix *p;
int command;
u_int16_t flags = 0;
size_t flags_pos = 0;
/* 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);
flags_pos = stream_get_endp (s); /* save position of 'flags' */
stream_putw(s, flags); /* initial flags */
stream_putw(s, PREFIX_FAMILY(p));
stream_put_prefix(s, p);
if (reg)
{
assert (ri);
if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
{
assert (ri->attr->extra);
flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
stream_putl (s, ri->attr->extra->label_index);
}
SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
}
else
UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
/* Set length and flags */
stream_putw_at (s, 0, stream_get_endp (s));
stream_putw_at (s, flags_pos, flags);
zclient_send_message(zclient);
}
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 = 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;
}

125
bgpd/bgp_label.h Normal file
View File

@ -0,0 +1,125 @@
/* 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, struct bgp_info *ri,
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, struct bgp_info *ri)
{
bgp_reg_dereg_for_label (rn, ri, 1);
}
static inline void
bgp_unregister_for_label (struct bgp_node *rn)
{
bgp_reg_dereg_for_label (rn, NULL, 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 */

View File

@ -237,6 +237,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)

View File

@ -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))

View File

@ -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])

View File

@ -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, mp_withdraw?NULL:attr, packet);
case SAFI_MPLS_VPN:
return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet);
case SAFI_ENCAP:

View File

@ -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"
@ -296,6 +298,20 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
}
}
static int
bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2)
{
u_int32_t ri1_label_index = BGP_INVALID_LABEL_INDEX;
u_int32_t ri2_label_index = BGP_INVALID_LABEL_INDEX;
if (ri1->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
ri1_label_index = ri1->attr->extra->label_index;
if (ri2->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
ri2_label_index = ri2->attr->extra->label_index;
return (!(ri1_label_index == ri2_label_index));
}
/* Set/unset bgp_info flags, adjusting any other state as needed.
* This is here primarily to keep prefix-count in check.
@ -1187,7 +1203,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 +1278,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 +1836,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);
@ -1914,7 +1946,39 @@ 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 except of the label index changes.
*/
bgp_table_lock (bgp_node_table (rn));
if (bgp_labeled_safi (safi))
{
if (new_select)
{
if (!old_select ||
bgp_label_index_differs (new_select, old_select) ||
new_select->sub_type != old_select->sub_type)
{
if (new_select->sub_type == BGP_ROUTE_STATIC &&
new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
{
if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
bgp_unregister_for_label (rn);
label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
bgp_set_valid_label(rn->local_label);
}
else
bgp_register_for_label (rn, new_select);
}
}
else if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
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 +1990,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 +2058,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 +2066,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 +2486,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 +2498,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 +2600,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 +2610,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 +2630,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 +2654,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 +2723,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 +2764,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 +2846,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 +2865,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 +2961,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)
@ -3702,9 +3790,9 @@ bgp_static_free (struct bgp_static *bgp_static)
XFREE (MTYPE_BGP_STATIC, bgp_static);
}
static void
bgp_static_update_main (struct bgp *bgp, struct prefix *p,
struct bgp_static *bgp_static, afi_t afi, safi_t safi)
void
bgp_static_update (struct bgp *bgp, struct prefix *p,
struct bgp_static *bgp_static, afi_t afi, safi_t safi)
{
struct bgp_node *rn;
struct bgp_info *ri;
@ -3732,6 +3820,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
if (bgp_static->atomic)
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
/* Store label index, if required. */
if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
{
(bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX);
}
/* Apply route-map. */
if (bgp_static->rmap.name)
{
@ -3818,9 +3913,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
{
@ -3903,13 +4000,6 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
bgp_attr_extra_free (&attr);
}
void
bgp_static_update (struct bgp *bgp, struct prefix *p,
struct bgp_static *bgp_static, afi_t afi, safi_t safi)
{
bgp_static_update_main (bgp, p, bgp_static, afi, safi);
}
void
bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
safi_t safi)
@ -4158,7 +4248,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
route should be installed as valid. */
static int
bgp_static_set (struct vty *vty, const char *ip_str,
afi_t afi, safi_t safi, const char *rmap, int backdoor)
afi_t afi, safi_t safi, const char *rmap, int backdoor,
u_int32_t label_index)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
@ -4191,6 +4282,13 @@ bgp_static_set (struct vty *vty, const char *ip_str,
/* Configuration change. */
bgp_static = rn->info;
/* Label index cannot be changed. */
if (bgp_static->label_index != label_index)
{
vty_out (vty, "%% Label index cannot be changed%s", VTY_NEWLINE);
return CMD_WARNING;
}
/* Check previous routes are installed into BGP. */
if (bgp_static->valid && bgp_static->backdoor != backdoor)
need_update = 1;
@ -4222,6 +4320,7 @@ bgp_static_set (struct vty *vty, const char *ip_str,
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
bgp_static->label_index = label_index;
if (rmap)
{
@ -4748,7 +4847,8 @@ DEFUN (bgp_network,
{
int idx_ipv4_prefixlen = 1;
return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg,
AFI_IP, bgp_node_safi (vty), NULL, 0);
AFI_IP, bgp_node_safi (vty), NULL, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_route_map,
@ -4762,7 +4862,8 @@ DEFUN (bgp_network_route_map,
int idx_ipv4_prefixlen = 1;
int idx_word = 3;
return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg,
AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_backdoor,
@ -4774,7 +4875,7 @@ DEFUN (bgp_network_backdoor,
{
int idx_ipv4_prefixlen = 1;
return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP, SAFI_UNICAST,
NULL, 1);
NULL, 1, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask,
@ -4798,7 +4899,7 @@ DEFUN (bgp_network_mask,
}
return bgp_static_set (vty, prefix_str,
AFI_IP, bgp_node_safi (vty), NULL, 0);
AFI_IP, bgp_node_safi (vty), NULL, 0, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_route_map,
@ -4825,7 +4926,7 @@ DEFUN (bgp_network_mask_route_map,
}
return bgp_static_set (vty, prefix_str,
AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_backdoor,
@ -4850,7 +4951,8 @@ DEFUN (bgp_network_mask_backdoor,
}
return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
NULL, 1);
NULL, 1,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural,
@ -4871,7 +4973,8 @@ DEFUN (bgp_network_mask_natural,
}
return bgp_static_set (vty, prefix_str,
AFI_IP, bgp_node_safi (vty), NULL, 0);
AFI_IP, bgp_node_safi (vty), NULL, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural_route_map,
@ -4895,7 +4998,8 @@ DEFUN (bgp_network_mask_natural_route_map,
}
return bgp_static_set (vty, prefix_str,
AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural_backdoor,
@ -4917,7 +5021,39 @@ DEFUN (bgp_network_mask_natural_backdoor,
}
return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
NULL, 1);
NULL, 1, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_label_index,
bgp_network_label_index_cmd,
"network A.B.C.D/M label-index (0-4294967294)",
"Specify a network to announce via BGP\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
"Label index to associate with the prefix\n"
"Label index value\n")
{
u_int32_t label_index;
VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
return bgp_static_set (vty, argv[1]->arg,
AFI_IP, bgp_node_safi (vty), NULL, 0, label_index);
}
DEFUN (bgp_network_label_index_route_map,
bgp_network_label_index_route_map_cmd,
"network A.B.C.D/M label-index (0-4294967294) route-map WORD",
"Specify a network to announce via BGP\n"
"IP prefix\n"
"Label index to associate with the prefix\n"
"Label index value\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
u_int32_t label_index;
VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
return bgp_static_set (vty, argv[1]->arg,
AFI_IP, bgp_node_safi (vty), argv[5]->arg, 0, label_index);
}
DEFUN (no_bgp_network,
@ -4988,6 +5124,26 @@ DEFUN (no_bgp_network_mask_natural,
bgp_node_safi (vty));
}
ALIAS (no_bgp_network,
no_bgp_network_label_index_cmd,
"no network A.B.C.D/M label-index (0-4294967294)",
NO_STR
"Specify a network to announce via BGP\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
"Label index to associate with the prefix\n"
"Label index value\n")
ALIAS (no_bgp_network,
no_bgp_network_label_index_route_map_cmd,
"no network A.B.C.D/M label-index (0-4294967294) route-map WORD",
NO_STR
"Specify a network to announce via BGP\n"
"IP prefix\n"
"Label index to associate with the prefix\n"
"Label index value\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
DEFUN (ipv6_bgp_network,
ipv6_bgp_network_cmd,
"network X:X::X:X/M",
@ -4996,7 +5152,8 @@ DEFUN (ipv6_bgp_network,
{
int idx_ipv6_prefixlen = 1;
return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty),
NULL, 0);
NULL, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (ipv6_bgp_network_route_map,
@ -5010,7 +5167,40 @@ DEFUN (ipv6_bgp_network_route_map,
int idx_ipv6_prefixlen = 1;
int idx_word = 3;
return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
bgp_node_safi (vty), argv[idx_word]->arg, 0);
bgp_node_safi (vty), argv[idx_word]->arg, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (ipv6_bgp_network_label_index,
ipv6_bgp_network_label_index_cmd,
"network X:X::X:X/M label-index (0-4294967294)",
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>\n"
"Label index to associate with the prefix\n"
"Label index value\n")
{
u_int32_t label_index;
VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
return bgp_static_set (vty, argv[1]->arg,
AFI_IP6, bgp_node_safi (vty), NULL, 0, label_index);
}
DEFUN (ipv6_bgp_network_label_index_route_map,
ipv6_bgp_network_label_index_route_map_cmd,
"network X:X::X:X/M label-index (0-4294967294) route-map WORD",
"Specify a network to announce via BGP\n"
"IPv6 prefix\n"
"Label index to associate with the prefix\n"
"Label index value\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
u_int32_t label_index;
VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
return bgp_static_set (vty, argv[1]->arg,
AFI_IP6, bgp_node_safi (vty), argv[5]->arg, 0, label_index);
}
DEFUN (no_ipv6_bgp_network,
@ -5026,6 +5216,26 @@ DEFUN (no_ipv6_bgp_network,
return bgp_static_unset (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty));
}
ALIAS (no_ipv6_bgp_network,
no_ipv6_bgp_network_label_index_cmd,
"no network X:X::X:X/M label-index (0-4294967294)",
NO_STR
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>\n"
"Label index to associate with the prefix\n"
"Label index value\n")
ALIAS (no_ipv6_bgp_network,
no_ipv6_bgp_network_label_index_route_map_cmd,
"no network X:X::X:X/M label-index (0-4294967294) route-map WORD",
NO_STR
"Specify a network to announce via BGP\n"
"IPv6 prefix\n"
"Label index to associate with the prefix\n"
"Label index value\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
/* Aggreagete address:
advertise-map Set condition to advertise attribute
@ -5557,6 +5767,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 +5827,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 +7653,28 @@ 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);
/* Label information */
if ((bgp_labeled_safi(safi) && binfo->extra) ||
(CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))))
{
if (bgp_labeled_safi(safi) && binfo->extra)
{
uint32_t label = label_pton(binfo->extra->tag);
if (json_paths)
json_object_int_add(json_path, "remoteLabel", label);
else
vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE);
}
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))
{
if (json_paths)
json_object_int_add(json_path, "labelIndex", attr->extra->label_index);
else
vty_out(vty, " Label Index: %d%s", attr->extra->label_index, VTY_NEWLINE);
}
}
/* Line 8 display Addpath IDs */
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
{
@ -7932,6 +8168,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)
@ -8213,7 +8461,7 @@ bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
DEFUN (show_ip_bgp_large_community_list,
show_ip_bgp_large_community_list_cmd,
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community-list <(1-500)|WORD> [json]",
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] large-community-list <(1-500)|WORD> [json]",
SHOW_STR
IP_STR
BGP_STR
@ -8224,6 +8472,7 @@ DEFUN (show_ip_bgp_large_community_list,
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Display routes matching the large-community-list\n"
"large-community-list number\n"
"large-community-list name\n"
@ -8259,7 +8508,7 @@ DEFUN (show_ip_bgp_large_community_list,
}
DEFUN (show_ip_bgp_large_community,
show_ip_bgp_large_community_cmd,
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community [AA:BB:CC] [json]",
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] large-community [AA:BB:CC] [json]",
SHOW_STR
IP_STR
BGP_STR
@ -8270,6 +8519,7 @@ DEFUN (show_ip_bgp_large_community,
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Display routes matching the large-communities\n"
"List of large-community numbers\n"
JSON_STR)
@ -9210,7 +9460,7 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, u_c
DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
show_ip_bgp_instance_neighbor_prefix_counts_cmd,
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] "
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] "
"neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
SHOW_STR
IP_STR
@ -9222,6 +9472,7 @@ DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
@ -10528,6 +10779,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
p->prefixlen);
}
if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
vty_out (vty, " label-index %u", bgp_static->label_index);
if (bgp_static->rmap.name)
vty_out (vty, " route-map %s", bgp_static->rmap.name);
else
@ -10654,6 +10908,8 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_route_map_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
@ -10681,6 +10937,21 @@ bgp_route_init (void)
install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd);
install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
/* IPv4 labeled-unicast configuration. */
install_element (BGP_IPV4L_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_mask_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_route_map_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_mask_route_map_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_route_map_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_label_index_cmd);
install_element (BGP_IPV4L_NODE, &bgp_network_label_index_route_map_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_network_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_natural_cmd);
install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd);
install_element (VIEW_NODE, &show_ip_bgp_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
@ -10714,6 +10985,10 @@ bgp_route_init (void)
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_cmd);
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_route_map_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_route_map_cmd);
install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
@ -10721,6 +10996,12 @@ bgp_route_init (void)
install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
install_element (BGP_IPV6L_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_route_map_cmd);
install_element (BGP_IPV6L_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV6L_NODE, &no_ipv6_bgp_network_cmd);
install_element (BGP_NODE, &bgp_distance_cmd);
install_element (BGP_NODE, &no_bgp_distance_cmd);
install_element (BGP_NODE, &bgp_distance_source_cmd);

View File

@ -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;
@ -179,6 +180,10 @@ struct bgp_static
/* Backdoor configuration. */
int backdoor;
/* Label index configuration; applies to LU prefixes. */
u_int32_t label_index;
#define BGP_INVALID_LABEL_INDEX 0xFFFFFFFF
/* Import check status. */
u_char valid;
@ -273,6 +278,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 +385,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);

View File

@ -56,10 +56,14 @@ 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)
#define BGP_NODE_REGISTERED_FOR_LABEL (1 << 3)
};
/*

View File

@ -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);

View File

@ -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,
@ -783,14 +787,26 @@ subgroup_update_packet (struct update_subgroup *subgrp)
{
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE w/ attr: %s",
subgrp->update_group->id, subgrp->id, send_attr_str);
if (!stream_empty (snlri))
{
iana_afi_t pkt_afi;
safi_t pkt_safi;
pkt_afi = afi_int2iana (afi);
pkt_safi = safi_int2iana (safi);
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_REACH for afi/safi %d/%d",
subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi);
}
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. */
@ -824,7 +840,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
packet = stream_dup (s);
bgp_packet_set_size (packet);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE len %zd numpfx %d",
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE len %zd numpfx %d",
subgrp->update_group->id, subgrp->id,
(stream_get_endp(packet) - stream_get_getp(packet)), num_pfx);
pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), packet, &vecarr);
@ -917,11 +933,20 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
/* If first time, format the MP_UNREACH header */
if (first_time)
{
iana_afi_t pkt_afi;
safi_t pkt_safi;
pkt_afi = afi_int2iana (afi);
pkt_safi = safi_int2iana (safi);
attrlen_pos = stream_get_endp (s);
/* total attr length = 0 for now. reevaluate later */
stream_putw (s, 0);
mp_start = stream_get_endp (s);
mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_UNREACH for afi/safi %d/%d",
subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi);
}
bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL,
@ -968,7 +993,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
}
bgp_packet_set_size (s);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE (withdraw) len %zd numpfx %d",
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE (withdraw) len %zd numpfx %d",
subgrp->update_group->id, subgrp->id,
(stream_get_endp(s) - stream_get_getp(s)), num_pfx);
pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), stream_dup (s), NULL);

View File

@ -60,6 +60,73 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
static struct peer_group *
listen_range_exists (struct bgp *bgp, struct prefix *range, int exact);
#if 0
#define INSTALL_CMD_ON_AF_NODES(cmd) \
install_element(BGP_IPV4_NODE, cmd); \
install_element(BGP_IPV4M_NODE, cmd); \
install_element(BGP_IPV4L_NODE, cmd); \
install_element(BGP_IPV6_NODE, cmd); \
install_element(BGP_IPV6M_NODE, cmd); \
install_element(BGP_IPV6L_NODE, cmd); \
install_element(BGP_VPNV4_NODE, cmd);
#endif
static enum node_type
bgp_node_type (afi_t afi, safi_t safi)
{
switch (afi)
{
case AFI_IP:
switch (safi)
{
case SAFI_UNICAST:
return BGP_IPV4_NODE;
break;
case SAFI_MULTICAST:
return BGP_IPV4M_NODE;
break;
case SAFI_LABELED_UNICAST:
return BGP_IPV4L_NODE;
break;
case SAFI_MPLS_VPN:
return BGP_VPNV4_NODE;
break;
case SAFI_ENCAP:
return BGP_ENCAP_NODE;
break;
}
break;
case AFI_IP6:
switch (safi)
{
case SAFI_UNICAST:
return BGP_IPV6_NODE;
break;
case SAFI_MULTICAST:
return BGP_IPV6M_NODE;
break;
case SAFI_LABELED_UNICAST:
return BGP_IPV6L_NODE;
break;
case SAFI_MPLS_VPN:
return BGP_VPNV6_NODE;
break;
case SAFI_ENCAP:
return BGP_ENCAP_NODE;
break;
}
break;
case AFI_L2VPN:
return BGP_EVPN_NODE;
break;
case AFI_MAX:
// We should never be here but to clarify the switch statement..
return BGP_IPV4_NODE;
break;
}
// Impossible to happen
return BGP_IPV4_NODE;
}
/* Utility function to get address family from current node. */
afi_t
@ -70,6 +137,7 @@ bgp_node_afi (struct vty *vty)
{
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_IPV6L_NODE:
case BGP_VPNV6_NODE:
case BGP_ENCAPV6_NODE:
afi = AFI_IP6;
@ -107,6 +175,10 @@ bgp_node_safi (struct vty *vty)
case BGP_EVPN_NODE:
safi = SAFI_EVPN;
break;
case BGP_IPV4L_NODE:
case BGP_IPV6L_NODE:
safi = SAFI_LABELED_UNICAST;
break;
default:
safi = SAFI_UNICAST;
break;
@ -160,7 +232,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af
return ret;
}
/* supports <unicast|multicast|vpn|encap> */
/* supports <unicast|multicast|vpn|encap|labeled-unicast> */
safi_t
bgp_vty_safi_from_arg(const char *safi_str)
{
@ -173,6 +245,8 @@ bgp_vty_safi_from_arg(const char *safi_str)
safi = SAFI_ENCAP;
else if (strncmp (safi_str, "v", 1) == 0)
safi = SAFI_MPLS_VPN;
else if (strncmp (safi_str, "l", 1) == 0)
safi = SAFI_LABELED_UNICAST;
return safi;
}
@ -192,6 +266,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
if (safi)
*safi = SAFI_MULTICAST;
}
else if (argv_find (argv, argc, "labeled-unicast", index))
{
ret = 1;
if (safi)
*safi = SAFI_LABELED_UNICAST;
}
else if (argv_find (argv, argc, "vpn", index))
{
ret = 1;
@ -223,12 +303,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
* that is being parsed.
*
* The show commands are generally of the form:
* "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] ..."
* "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] ..."
*
* Since we use argv_find if the show command in particular doesn't have:
* [ip]
* [<view|vrf> WORD]
* [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]
* [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]]
* The command parsing should still be ok.
*
* vty -> The vty for the command so we can output some useful data in
@ -5649,30 +5729,16 @@ DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
DEFUN_NOSH (address_family_ipv4_safi,
address_family_ipv4_safi_cmd,
"address-family ipv4 [<unicast|multicast|vpn|encap>]",
"address-family ipv4 [<unicast|multicast|vpn|encap|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
BGP_SAFI_HELP_STR)
{
int idx_safi = 2;
if (argc == (idx_safi + 1))
if (argc == 3)
{
switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg))
{
case SAFI_MULTICAST:
vty->node = BGP_IPV4M_NODE;
break;
case SAFI_ENCAP:
vty->node = BGP_ENCAP_NODE;
break;
case SAFI_MPLS_VPN:
vty->node = BGP_VPNV4_NODE;
break;
case SAFI_UNICAST:
default:
vty->node = BGP_IPV4_NODE;
break;
}
safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg);
vty->node = bgp_node_type(AFI_IP, safi);
}
else
vty->node = BGP_IPV4_NODE;
@ -5682,30 +5748,15 @@ DEFUN_NOSH (address_family_ipv4_safi,
DEFUN_NOSH (address_family_ipv6_safi,
address_family_ipv6_safi_cmd,
"address-family ipv6 [<unicast|multicast|vpn|encap>]",
"address-family ipv6 [<unicast|multicast|vpn|encap|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
BGP_SAFI_HELP_STR)
{
int idx_safi = 2;
if (argc == (idx_safi + 1))
if (argc == 3)
{
switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg))
{
case SAFI_MULTICAST:
vty->node = BGP_IPV6M_NODE;
break;
case SAFI_ENCAP:
vty->node = BGP_ENCAPV6_NODE;
break;
case SAFI_MPLS_VPN:
vty->node = BGP_VPNV6_NODE;
break;
case SAFI_UNICAST:
default:
vty->node = BGP_IPV6_NODE;
break;
}
safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg);
vty->node = bgp_node_type(AFI_IP6, safi);
}
else
vty->node = BGP_IPV6_NODE;
@ -5778,9 +5829,11 @@ DEFUN_NOSH (exit_address_family,
{
if (vty->node == BGP_IPV4_NODE
|| vty->node == BGP_IPV4M_NODE
|| vty->node == BGP_IPV4L_NODE
|| vty->node == BGP_VPNV4_NODE
|| vty->node == BGP_IPV6_NODE
|| vty->node == BGP_IPV6M_NODE
|| vty->node == BGP_IPV6L_NODE
|| vty->node == BGP_VPNV6_NODE
|| vty->node == BGP_ENCAP_NODE
|| vty->node == BGP_ENCAPV6_NODE
@ -6871,6 +6924,8 @@ afi_safi_print (afi_t afi, safi_t safi)
return "IPv4 Unicast";
else if (afi == AFI_IP && safi == SAFI_MULTICAST)
return "IPv4 Multicast";
else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
return "IPv4 labeled-unicast";
else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
return "IPv4 VPN";
else if (afi == AFI_IP && safi == SAFI_ENCAP)
@ -6879,6 +6934,8 @@ afi_safi_print (afi_t afi, safi_t safi)
return "IPv6 Unicast";
else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
return "IPv6 Multicast";
else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
return "IPv6 labeled-unicast";
else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
return "IPv6 VPN";
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
@ -6896,6 +6953,8 @@ afi_safi_json (afi_t afi, safi_t safi)
return "IPv4Unicast";
else if (afi == AFI_IP && safi == SAFI_MULTICAST)
return "IPv4Multicast";
else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
return "IPv4LabeledUnicast";
else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
return "IPv4VPN";
else if (afi == AFI_IP && safi == SAFI_ENCAP)
@ -6904,6 +6963,8 @@ afi_safi_json (afi_t afi, safi_t safi)
return "IPv6Unicast";
else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
return "IPv6Multicast";
else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
return "IPv6LabeledUnicast";
else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
return "IPv6VPN";
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
@ -10033,6 +10094,13 @@ static struct cmd_node bgp_ipv4_multicast_node =
1,
};
static struct cmd_node bgp_ipv4_labeled_unicast_node =
{
BGP_IPV4L_NODE,
"%s(config-router-af)# ",
1,
};
static struct cmd_node bgp_ipv6_unicast_node =
{
BGP_IPV6_NODE,
@ -10047,6 +10115,13 @@ static struct cmd_node bgp_ipv6_multicast_node =
1,
};
static struct cmd_node bgp_ipv6_labeled_unicast_node =
{
BGP_IPV6L_NODE,
"%s(config-router-af)# ",
1,
};
static struct cmd_node bgp_vpnv4_node =
{
BGP_VPNV4_NODE,
@ -10091,8 +10166,10 @@ bgp_vty_init (void)
install_node (&bgp_node, bgp_config_write);
install_node (&bgp_ipv4_unicast_node, NULL);
install_node (&bgp_ipv4_multicast_node, NULL);
install_node (&bgp_ipv4_labeled_unicast_node, NULL);
install_node (&bgp_ipv6_unicast_node, NULL);
install_node (&bgp_ipv6_multicast_node, NULL);
install_node (&bgp_ipv6_labeled_unicast_node, NULL);
install_node (&bgp_vpnv4_node, NULL);
install_node (&bgp_vpnv6_node, NULL);
install_node (&bgp_encap_node, NULL);
@ -10103,8 +10180,10 @@ bgp_vty_init (void)
install_default (BGP_NODE);
install_default (BGP_IPV4_NODE);
install_default (BGP_IPV4M_NODE);
install_default (BGP_IPV4L_NODE);
install_default (BGP_IPV6_NODE);
install_default (BGP_IPV6M_NODE);
install_default (BGP_IPV6L_NODE);
install_default (BGP_VPNV4_NODE);
install_default (BGP_VPNV6_NODE);
install_default (BGP_ENCAP_NODE);
@ -10180,15 +10259,27 @@ bgp_vty_init (void)
install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd);
install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd);
install_element(BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd);
install_element(BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd);
install_element(BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV4L_NODE, &bgp_maxpaths_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_cmd);
install_element (BGP_IPV6L_NODE, &bgp_maxpaths_cmd);
install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_cmd);
install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cmd);
install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd);
/* "timers bgp" commands. */
install_element (BGP_NODE, &bgp_timers_cmd);
install_element (BGP_NODE, &no_bgp_timers_cmd);
@ -10317,8 +10408,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV4_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV6_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_activate_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd);
install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd);
@ -10329,8 +10422,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_activate_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd);
@ -10346,8 +10441,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd);
install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd);
@ -10357,8 +10454,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd);
install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd);
@ -10369,12 +10468,16 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd);
@ -10391,10 +10494,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd);
@ -10420,10 +10527,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd);
@ -10440,10 +10551,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_force_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_force_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd);
@ -10456,10 +10571,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV6_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_as_override_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_as_override_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_as_override_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_as_override_cmd);
@ -10490,6 +10609,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_all_cmd);
@ -10506,6 +10633,14 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_all_cmd);
@ -10540,6 +10675,10 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_send_community_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_type_cmd);
install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd);
install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd);
@ -10548,6 +10687,10 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_send_community_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_type_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd);
@ -10572,10 +10715,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd);
@ -10592,10 +10739,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd);
@ -10612,10 +10763,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
@ -10628,10 +10783,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
@ -10659,10 +10818,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd);
/* "neighbor capability dynamic" commands.*/
install_element (BGP_NODE, &neighbor_capability_dynamic_cmd);
@ -10699,12 +10862,18 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_default_originate_cmd);
install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_default_originate_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_default_originate_rmap_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_default_originate_cmd);
/* "neighbor port" commands. */
install_element (BGP_NODE, &neighbor_port_cmd);
@ -10718,10 +10887,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV6_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_weight_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_weight_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_weight_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_weight_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_weight_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_weight_cmd);
@ -10762,10 +10935,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd);
@ -10782,10 +10959,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd);
@ -10802,10 +10983,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_filter_list_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd);
@ -10822,10 +11007,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_route_map_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd);
@ -10842,10 +11031,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
@ -10877,6 +11070,13 @@ bgp_vty_init (void)
install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_warning_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_restart_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_cmd);
install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd);
install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd);
install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd);
@ -10891,6 +11091,13 @@ bgp_vty_init (void)
install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_warning_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_restart_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd);
@ -10929,10 +11136,14 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV4L_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV4L_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_IPV6L_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_IPV6L_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd);
@ -10958,8 +11169,10 @@ bgp_vty_init (void)
/* "exit-address-family" command. */
install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4L_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6L_NODE, &exit_address_family_cmd);
install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);

View File

@ -28,8 +28,10 @@ struct bgp;
#define BGP_AFI_CMD_STR "<ipv4|ipv6>"
#define BGP_AFI_HELP_STR "Address Family\nAddress Family\n"
#define BGP_SAFI_CMD_STR "<unicast|multicast|vpn|encap>"
#define BGP_SAFI_CMD_STR "<unicast|multicast|vpn|encap|labeled-unicast>"
#define BGP_SAFI_HELP_STR \
"Address Family modifier\n" \
"Address Family modifier\n" \
"Address Family modifier\n" \
"Address Family modifier\n" \
"Address Family modifier\n" \

View File

@ -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,9 +2268,11 @@ 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);
bgp_label_buf = stream_new(BGP_LABEL_BUF_SIZE);
}
void

View File

@ -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);

View File

@ -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;
@ -7262,6 +7270,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
{
if (safi == SAFI_UNICAST)
vty_out (vty, "ipv4 unicast");
else if (safi == SAFI_LABELED_UNICAST)
vty_out (vty, "ipv4 labeled-unicast");
else if (safi == SAFI_MULTICAST)
vty_out (vty, "ipv4 multicast");
else if (safi == SAFI_MPLS_VPN)
@ -7273,6 +7283,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
{
if (safi == SAFI_UNICAST)
vty_out (vty, "ipv6 unicast");
else if (safi == SAFI_LABELED_UNICAST)
vty_out (vty, "ipv6 labeled-unicast");
else if (safi == SAFI_MULTICAST)
vty_out (vty, "ipv6 multicast");
else if (safi == SAFI_MPLS_VPN)
@ -7579,6 +7591,9 @@ bgp_config_write (struct vty *vty)
/* IPv4 multicast configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST);
/* IPv4 labeled-unicast configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_LABELED_UNICAST);
/* IPv4 VPN configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN);
@ -7591,6 +7606,9 @@ bgp_config_write (struct vty *vty)
/* IPv6 multicast configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST);
/* IPv6 labeled-unicast configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_LABELED_UNICAST);
/* IPv6 VPN configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN);

View File

@ -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
};
@ -971,6 +973,7 @@ struct bgp_nlri
#define BGP_ATTR_AS_PATHLIMIT 21
#define BGP_ATTR_ENCAP 23
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_LABEL_INDEX 40
#if ENABLE_BGP_VNC
#define BGP_ATTR_VNC 255
#endif
@ -1394,6 +1397,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 +1420,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 +1465,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 +1480,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;

View File

@ -369,11 +369,11 @@ dnl ----------
AC_MSG_CHECKING(whether this OS has MPLS stack)
case "$host" in
*-linux*)
MPLS_METHOD="zebra_mpls_netlink.o"
MPLS_METHOD="zebra_mpls_netlink.o zebra_mpls.o"
AC_MSG_RESULT(Linux MPLS)
;;
*-openbsd*)
MPLS_METHOD="zebra_mpls_openbsd.o"
MPLS_METHOD="zebra_mpls_openbsd.o zebra_mpls.o"
AC_MSG_RESULT(OpenBSD MPLS)
;;
*)

1
debian/frr.dirs vendored
View File

@ -1,5 +1,6 @@
etc/logrotate.d/
etc/frr/
etc/iproute2/rt_protos.d/
usr/share/doc/frr/
usr/share/doc/frr/examples/
usr/share/lintian/overrides/

1
debian/frr.install vendored
View File

@ -18,5 +18,6 @@ usr/share/man/man8/isisd.8
usr/share/man/man8/watchfrr.8
usr/share/snmp/mibs/
cumulus/etc/* etc/
tools/etc/* etc/
tools/*.service lib/systemd/system
debian/frr.conf usr/lib/tmpfiles.d

View File

@ -38,6 +38,7 @@ an example.)
cd frr
./bootstrap.sh
./configure \
--prefix=/usr \
--enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
@ -110,3 +111,38 @@ Add the following lines to `/etc/modules-load.d/modules.conf`:
mpls-iptunnel
**Reboot** or use `sysctl -p` to apply the same config to the running system
### Install the systemd service
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
sudo install -m 644 cumulus/etc/default/frr /etc/default/frr
sudo install -m 644 cumulus/etc/frr/daemons /etc/frr/daemons
sudo install -m 644 cumulus/etc/frr/debian.conf /etc/frr/debian.conf
sudo install -m 644 cumulus/etc/frr/Frr.conf /etc/frr/Frr.conf
sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf
### Enable daemons
Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd.
For example.
zebra=yes
bgpd=yes
ospfd=yes
ospf6d=yes
ripd=yes
ripngd=yes
isisd=yes
### Enable the systemd serivce
Edit `/etc/systemd/system/frr.service` and remove the line **OnFailure=heartbeat-failed@%n.service**
For example.
[Unit]
Description=Cumulus Linux FRR
After=syslog.target networking.service
   
### Start the systemd service
- systemctl start frr
- use `systemctl status frr` to check its status.

View File

@ -16,7 +16,7 @@ libisis_a_SOURCES = \
isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
isis_vty.c
isis_vty.c isis_mt.c
noinst_HEADERS = \
@ -25,7 +25,7 @@ noinst_HEADERS = \
isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
isis_route.h isis_routemap.h isis_te.h
isis_route.h isis_routemap.h isis_te.h isis_mt.h
isisd_SOURCES = \
isis_main.c $(libisis_a_SOURCES) \

View File

@ -47,6 +47,7 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_events.h"
#include "isisd/isis_mt.h"
extern struct isis *isis;
@ -148,6 +149,8 @@ isis_delete_adj (void *arg)
if (adj->ipv6_addrs)
list_delete (adj->ipv6_addrs);
adj_mt_finish(adj);
XFREE (MTYPE_ISIS_ADJACENCY, adj);
return;
}
@ -521,3 +524,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list)
return;
}
int
isis_adj_usage2levels(enum isis_adj_usage usage)
{
switch (usage)
{
case ISIS_ADJ_LEVEL1:
return IS_LEVEL_1;
case ISIS_ADJ_LEVEL2:
return IS_LEVEL_2;
case ISIS_ADJ_LEVEL1AND2:
return IS_LEVEL_1 | IS_LEVEL_2;
default:
break;
}
return 0;
}

View File

@ -97,6 +97,8 @@ struct isis_adjacency
int flaps; /* number of adjacency flaps */
struct thread *t_expire; /* expire after hold_time */
struct isis_circuit *circuit; /* back pointer */
uint16_t *mt_set; /* Topologies this adjacency is valid for */
unsigned int mt_count; /* Number of entries in mt_set */
};
struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb);
@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread);
void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);
void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
void isis_adj_build_up_list (struct list *adjdb, struct list *list);
int isis_adj_usage2levels(enum isis_adj_usage usage);
#endif /* ISIS_ADJACENCY_H */

View File

@ -212,16 +212,11 @@ isis_sock_init (struct isis_circuit *circuit)
goto end;
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
if (if_is_broadcast(circuit->interface))
{
circuit->tx = isis_send_pdu_bcast;
circuit->rx = isis_recv_pdu_bcast;
}
else if (circuit->circ_type == CIRCUIT_T_P2P)
{
circuit->tx = isis_send_pdu_p2p;
circuit->rx = isis_recv_pdu_p2p;
}
else
{
zlog_warn ("isis_sock_init(): unknown circuit type");
@ -283,23 +278,6 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
return ISIS_OK;
}
int
isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
{
int bytesread;
bytesread = stream_read (circuit->rcv_stream, circuit->fd,
circuit->interface->mtu);
if (bytesread < 0)
{
zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
return ISIS_WARNING;
}
return ISIS_OK;
}
int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
@ -327,7 +305,8 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
else
memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
eth->ether_type = htons(isis_ethertype(frame_size));
/*
* Then the LLC
@ -354,10 +333,4 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
return ISIS_OK;
}
int
isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
{
return ISIS_OK;
}
#endif /* ISIS_METHOD == ISIS_METHOD_BPF */

View File

@ -60,6 +60,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
DEFINE_QOBJ_TYPE(isis_circuit)
@ -102,6 +103,8 @@ isis_circuit_new ()
circuit->mtc = mpls_te_circuit_new();
circuit_mt_init(circuit);
QOBJ_REG (circuit, isis_circuit);
return circuit;
@ -117,6 +120,8 @@ isis_circuit_del (struct isis_circuit *circuit)
isis_circuit_if_unbind (circuit, circuit->interface);
circuit_mt_finish(circuit);
/* and lastly the circuit itself */
XFREE (MTYPE_ISIS_CIRCUIT, circuit);
@ -1215,6 +1220,7 @@ isis_interface_config_write (struct vty *vty)
VTY_NEWLINE);
write++;
}
write += circuit_write_mt_settings(circuit, vty);
}
vty_out (vty, "!%s", VTY_NEWLINE);
}
@ -1382,6 +1388,22 @@ isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
return 0;
}
int
isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid,
bool enabled)
{
struct isis_circuit_mt_setting *setting;
setting = circuit_get_mt_setting(circuit, mtid);
if (setting->enabled != enabled)
{
setting->enabled = enabled;
lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
}
return CMD_SUCCESS;
}
int
isis_if_new_hook (struct interface *ifp)
{

View File

@ -123,6 +123,7 @@ struct isis_circuit
struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */
int ip_router; /* Route IP ? */
int is_passive; /* Is Passive ? */
struct list *mt_settings; /* IS-IS MT Settings */
struct list *ip_addrs; /* our IP addresses */
int ipv6_router; /* Route IPv6 ? */
struct list *ipv6_link; /* our link local IPv6 addresses */
@ -187,4 +188,6 @@ int isis_circuit_passwd_unset (struct isis_circuit *circuit);
int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd);
int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd);
int isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid, bool enabled);
#endif /* _ZEBRA_ISIS_CIRCUIT_H */

View File

@ -171,4 +171,14 @@
#define ETH_ALEN 6
#endif
#define MAX_LLC_LEN 0x5ff
#define ETHERTYPE_EXT_LLC 0x8870
static inline uint16_t isis_ethertype(size_t len)
{
if (len > MAX_LLC_LEN)
return ETHERTYPE_EXT_LLC;
return len;
}
#endif /* ISIS_CONSTANTS_H */

View File

@ -53,6 +53,7 @@
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
/* staticly assigned vars for printing purposes */
char lsp_bits_string[200]; /* FIXME: enough ? */
@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
expected |= TLVFLAG_TE_IPV4_REACHABILITY;
expected |= TLVFLAG_TE_ROUTER_ID;
}
expected |= TLVFLAG_MT_ROUTER_INFORMATION;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV4_INT_REACHABILITY;
expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
@ -826,6 +828,107 @@ lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
}
static void
lsp_print_mt_reach(struct list *list, struct vty *vty,
char dynhost, uint16_t mtid)
{
struct listnode *node;
struct te_is_neigh *neigh;
for (ALL_LIST_ELEMENTS_RO (list, node, neigh))
{
u_char lspid[255];
lspid_print(neigh->neigh_id, lspid, dynhost, 0);
if (mtid == ISIS_MT_IPV4_UNICAST)
{
vty_out(vty, " Metric : %-8d IS-Extended : %s%s",
GET_TE_METRIC(neigh), lspid, VTY_NEWLINE);
}
else
{
vty_out(vty, " Metric : %-8d MT-Reach : %s %s%s",
GET_TE_METRIC(neigh), lspid,
isis_mtid2str(mtid), VTY_NEWLINE);
}
if (IS_MPLS_TE(isisMplsTE))
mpls_te_print_detail(vty, neigh);
}
}
static void
lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty, uint16_t mtid)
{
struct listnode *node;
struct ipv6_reachability *ipv6_reach;
struct in6_addr in6;
u_char buff[BUFSIZ];
for (ALL_LIST_ELEMENTS_RO (list, node, ipv6_reach))
{
memset (&in6, 0, sizeof (in6));
memcpy (in6.s6_addr, ipv6_reach->prefix,
PSIZE (ipv6_reach->prefix_len));
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
if (mtid == ISIS_MT_IPV4_UNICAST)
{
if ((ipv6_reach->control_info &
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
else
vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
}
else
{
if ((ipv6_reach->control_info &
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
vty_out (vty, " Metric : %-8d IPv6-MT-Int : %s/%d %s%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len,
isis_mtid2str(mtid), VTY_NEWLINE);
else
vty_out (vty, " Metric : %-8d IPv6-MT-Ext : %s/%d %s%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len,
isis_mtid2str(mtid), VTY_NEWLINE);
}
}
}
static void
lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty, uint16_t mtid)
{
struct listnode *node;
struct te_ipv4_reachability *te_ipv4_reach;
for (ALL_LIST_ELEMENTS_RO (list, node, te_ipv4_reach))
{
if (mtid == ISIS_MT_IPV4_UNICAST)
{
/* FIXME: There should be better way to output this stuff. */
vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
ntohl (te_ipv4_reach->te_metric),
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
te_ipv4_reach->control)),
te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
}
else
{
/* FIXME: There should be better way to output this stuff. */
vty_out (vty, " Metric : %-8d IPv4-MT : %s/%d %s%s",
ntohl (te_ipv4_reach->te_metric),
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
te_ipv4_reach->control)),
te_ipv4_reach->control & 0x3F,
isis_mtid2str(mtid), VTY_NEWLINE);
}
}
}
void
lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
{
@ -833,13 +936,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
int i;
struct listnode *lnode;
struct is_neigh *is_neigh;
struct te_is_neigh *te_is_neigh;
struct ipv4_reachability *ipv4_reach;
struct in_addr *ipv4_addr;
struct te_ipv4_reachability *te_ipv4_reach;
struct ipv6_reachability *ipv6_reach;
struct in6_addr in6;
u_char buff[BUFSIZ];
struct mt_router_info *mt_router_info;
struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
struct tlv_mt_neighbors *mt_is_neigh;
struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
u_char LSPid[255];
u_char hostname[255];
u_char ipv4_reach_prefix[20];
@ -877,6 +979,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
}
}
for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
{
vty_out (vty, " MT : %s%s%s",
isis_mtid2str(mt_router_info->mtid),
mt_router_info->overload ? " (overload)" : "",
VTY_NEWLINE);
}
/* for the hostname tlv */
if (lsp->tlv_data.hostname)
{
@ -946,49 +1056,31 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
ipv4_reach_mask, VTY_NEWLINE);
}
/* IPv6 tlv */
if (lsp->tlv_data.ipv6_reachs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
{
memset (&in6, 0, sizeof (in6));
memcpy (in6.s6_addr, ipv6_reach->prefix,
PSIZE (ipv6_reach->prefix_len));
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
if ((ipv6_reach->control_info &
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
else
vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
}
lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
ISIS_MT_IPV4_UNICAST);
/* MT IPv6 reachability tlv */
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv6_reachs, lnode, mt_ipv6_reachs))
lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty, mt_ipv6_reachs->mtid);
/* TE IS neighbor tlv */
if (lsp->tlv_data.te_is_neighs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
{
lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
if (IS_MPLS_TE(isisMplsTE))
mpls_te_print_detail(vty, te_is_neigh);
}
lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty,
dynhost, ISIS_MT_IPV4_UNICAST);
/* MT IS neighbor tlv */
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_is_neighs, lnode, mt_is_neigh))
lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, mt_is_neigh->mtid);
/* TE IPv4 tlv */
if (lsp->tlv_data.te_ipv4_reachs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
te_ipv4_reach))
{
/* FIXME: There should be better way to output this stuff. */
vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
ntohl (te_ipv4_reach->te_metric),
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
te_ipv4_reach->control)),
te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
}
lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
ISIS_MT_IPV4_UNICAST);
/* MT IPv4 reachability tlv */
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv4_reachs, lnode, mt_ipv4_reachs))
lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty, mt_ipv4_reachs->mtid);
vty_out (vty, "%s", VTY_NEWLINE);
return;
@ -1028,6 +1120,42 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
return lsp_count;
}
static void
_lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
int frag_thold,
unsigned int tlv_build_func (struct list *, struct stream *,
void *arg),
void *arg)
{
while (*from && listcount(*from))
{
unsigned int count;
count = tlv_build_func(*from, lsp->pdu, arg);
if (listcount(*to) != 0 || count != listcount(*from))
{
struct listnode *node, *nnode;
void *elem;
for (ALL_LIST_ELEMENTS(*from, node, nnode, elem))
{
if (!count)
break;
listnode_add (*to, elem);
list_delete_node (*from, node);
--count;
}
}
else
{
list_free (*to);
*to = *from;
*from = NULL;
}
}
}
#define FRAG_THOLD(S,T) \
((STREAM_SIZE(S)*T)/100)
@ -1085,64 +1213,6 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
return;
}
/* Process IS_NEIGHBOURS TLV with TE subTLVs */
void
lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
{
int count, size = 0;
struct listnode *node, *nextnode;
struct te_is_neigh *elem;
/* Start computing real size of TLVs */
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
/* can we fit all ? */
if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
{
tlv_add_te_is_neighs (*from, lsp->pdu);
if (listcount (*to) != 0)
{
for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
{
listnode_add (*to, elem);
list_delete_node (*from, node);
}
}
else
{
list_free (*to);
*to = *from;
*from = NULL;
}
}
else
{
/* fit all we can */
/* Compute remaining place in LSP PDU */
count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
(STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
/* Determine size of TE SubTLVs */
elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
if (count > 0)
{
while (count > 0)
{
listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
}
tlv_add_te_is_neighs (*to, lsp->pdu);
}
}
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
return;
}
static u_int16_t
lsp_rem_lifetime (struct isis_area *area, int level)
{
@ -1278,6 +1348,24 @@ lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
}
}
static struct list *
tlv_get_ipv6_reach_list(struct isis_area *area, struct tlvs *tlv_data)
{
uint16_t mtid = isis_area_ipv6_topology(area);
if (mtid == ISIS_MT_IPV4_UNICAST)
{
if (!tlv_data->ipv6_reachs)
{
tlv_data->ipv6_reachs = list_new();
tlv_data->ipv6_reachs->del = free_tlv;
}
return tlv_data->ipv6_reachs;
}
struct tlv_mt_ipv6_reachs *reachs = tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
return reachs->list;
}
static void
lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
struct tlvs *tlv_data)
@ -1287,6 +1375,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
struct prefix_ipv6 *ipv6;
struct isis_ext_info *info;
struct ipv6_reachability *ip6reach;
struct list *reach_list = NULL;
er_table = get_ext_reach(area, AF_INET6, lsp->level);
if (!er_table)
@ -1300,11 +1389,9 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
ipv6 = (struct prefix_ipv6*)&rn->p;
info = rn->info;
if (tlv_data->ipv6_reachs == NULL)
{
tlv_data->ipv6_reachs = list_new();
tlv_data->ipv6_reachs->del = free_tlv;
}
if (!reach_list)
reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
if (info->metric > MAX_WIDE_PATH_METRIC)
ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
@ -1313,7 +1400,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
ip6reach->control_info = DISTRIBUTION_EXTERNAL;
ip6reach->prefix_len = ipv6->prefixlen;
memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
listnode_add(tlv_data->ipv6_reachs, ip6reach);
listnode_add(reach_list, ip6reach);
}
}
@ -1342,6 +1429,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
struct te_ipv4_reachability *te_ipreach;
struct isis_adjacency *nei;
struct prefix_ipv6 *ipv6, ip6prefix;
struct list *ipv6_reachs = NULL;
struct ipv6_reachability *ip6reach;
struct tlvs tlv_data;
struct isis_lsp *lsp0 = lsp;
@ -1402,6 +1490,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
}
if (area_is_mt(area))
{
lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
lsp->tlv_data.mt_router_info = list_new();
lsp->tlv_data.mt_router_info->del = free_tlv;
struct isis_area_mt_setting **mt_settings;
unsigned int mt_count;
mt_settings = area_mt_settings(area, &mt_count);
for (unsigned int i = 0; i < mt_count; i++)
{
struct mt_router_info *info;
info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
info->mtid = mt_settings[i]->mtid;
info->overload = mt_settings[i]->overload;
listnode_add(lsp->tlv_data.mt_router_info, info);
lsp_debug("ISIS (%s): MT %s", area->area_tag, isis_mtid2str(info->mtid));
}
tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu);
}
else
{
lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag);
}
/* Dynamic Hostname */
if (area->dynhostname)
{
@ -1551,12 +1665,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
if (circuit->ipv6_router && circuit->ipv6_non_link &&
circuit->ipv6_non_link->count > 0)
{
if (!ipv6_reachs)
ipv6_reachs = tlv_get_ipv6_reach_list(area, &tlv_data);
if (tlv_data.ipv6_reachs == NULL)
{
tlv_data.ipv6_reachs = list_new ();
tlv_data.ipv6_reachs->del = free_tlv;
}
for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
{
ip6reach =
@ -1579,7 +1690,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
sizeof (ip6reach->prefix));
listnode_add (tlv_data.ipv6_reachs, ip6reach);
listnode_add (ipv6_reachs, ip6reach);
}
}
@ -1658,10 +1769,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
te_is_neigh->sub_tlvs_length = 0;
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
area->area_tag, sysid_print(te_is_neigh->neigh_id),
LSP_PSEUDO_ID(te_is_neigh->neigh_id));
tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh);
XFREE(MTYPE_ISIS_TLV, te_is_neigh);
}
}
}
@ -1718,9 +1827,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
else
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
te_is_neigh->sub_tlvs_length = 0;
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
sysid_print(te_is_neigh->neigh_id));
tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh);
XFREE(MTYPE_ISIS_TLV, te_is_neigh);
}
}
else
@ -1766,35 +1875,62 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
lsp0, area, level);
}
/* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
* for now. lsp_tlv_fit() needs to be fixed to deal with variable length
* TLVs (sub TLVs!). */
while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
{
if (lsp->tlv_data.te_ipv4_reachs == NULL)
lsp->tlv_data.te_ipv4_reachs = list_new ();
lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
&lsp->tlv_data.te_ipv4_reachs,
TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
tlv_add_te_ipv4_reachs);
_lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs,
area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, NULL);
if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node, mt_ipv4_reachs))
{
while (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
{
struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(&lsp->tlv_data, mt_ipv4_reachs->mtid);
_lsp_tlv_fit (lsp, &mt_ipv4_reachs->list, &frag_mt_ipv4_reachs->list,
area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
&mt_ipv4_reachs->mtid);
if (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
}
while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
{
if (lsp->tlv_data.ipv6_reachs == NULL)
lsp->tlv_data.ipv6_reachs = list_new ();
lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
&lsp->tlv_data.ipv6_reachs,
IPV6_REACH_LEN, area->lsp_frag_threshold,
tlv_add_ipv6_reachs);
_lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node, mt_ipv6_reachs))
{
while (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
{
struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(&lsp->tlv_data, mt_ipv6_reachs->mtid);
_lsp_tlv_fit (lsp, &mt_ipv6_reachs->list, &frag_mt_ipv6_reachs->list,
area->lsp_frag_threshold, tlv_add_ipv6_reachs,
&mt_ipv6_reachs->mtid);
if (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
}
while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
{
if (lsp->tlv_data.is_neighs == NULL)
@ -1812,13 +1948,31 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
{
if (lsp->tlv_data.te_is_neighs == NULL)
lsp->tlv_data.te_is_neighs = list_new ();
lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
tlv_add_te_is_neighs);
_lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
area->lsp_frag_threshold, tlv_add_te_is_neighs, NULL);
if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
struct tlv_mt_neighbors *mt_neighs;
for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs))
{
while (mt_neighs->list && listcount(mt_neighs->list))
{
struct tlv_mt_neighbors *frag_mt_neighs;
frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data, mt_neighs->mtid);
_lsp_tlv_fit (lsp, &mt_neighs->list, &frag_mt_neighs->list,
area->lsp_frag_threshold, tlv_add_te_is_neighs,
&mt_neighs->mtid);
if (mt_neighs->list && listcount(mt_neighs->list))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
}
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
free_tlvs (&tlv_data);
@ -2255,7 +2409,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu, NULL);
if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);

View File

@ -108,8 +108,6 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
char dynhost);
const char *lsp_bits2string (u_char *);
void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from,
struct list **to, int frag_thold);
/* sets SRMflags for all active circuits of an lsp */
void lsp_set_all_srmflags (struct isis_lsp *lsp);

724
isisd/isis_mt.c Normal file
View File

@ -0,0 +1,724 @@
/*
* IS-IS Rout(e)ing protocol - Multi Topology Support
*
* Copyright (C) 2017 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
* FRR 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.
*
* FRR 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 FRR; 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 "isisd/isisd.h"
#include "isisd/isis_memory.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_tlv.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_mt.h"
DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
uint16_t isis_area_ipv6_topology(struct isis_area *area)
{
struct isis_area_mt_setting *area_mt_setting;
area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST);
if (area_mt_setting && area_mt_setting->enabled)
return ISIS_MT_IPV6_UNICAST;
return ISIS_MT_IPV4_UNICAST;
}
/* MT naming api */
const char *isis_mtid2str(uint16_t mtid)
{
static char buf[sizeof("65535")];
switch(mtid)
{
case ISIS_MT_IPV4_UNICAST:
return "ipv4-unicast";
case ISIS_MT_IPV4_MGMT:
return "ipv4-mgmt";
case ISIS_MT_IPV6_UNICAST:
return "ipv6-unicast";
case ISIS_MT_IPV4_MULTICAST:
return "ipv4-multicast";
case ISIS_MT_IPV6_MULTICAST:
return "ipv6-multicast";
case ISIS_MT_IPV6_MGMT:
return "ipv6-mgmt";
default:
snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
return buf;
}
}
uint16_t isis_str2mtid(const char *name)
{
if (!strcmp(name,"ipv4-unicast"))
return ISIS_MT_IPV4_UNICAST;
if (!strcmp(name,"ipv4-mgmt"))
return ISIS_MT_IPV4_MGMT;
if (!strcmp(name,"ipv6-unicast"))
return ISIS_MT_IPV6_UNICAST;
if (!strcmp(name,"ipv4-multicast"))
return ISIS_MT_IPV4_MULTICAST;
if (!strcmp(name,"ipv6-multicast"))
return ISIS_MT_IPV6_MULTICAST;
if (!strcmp(name,"ipv6-mgmt"))
return ISIS_MT_IPV6_MGMT;
return -1;
}
/* General MT settings api */
struct mt_setting {
ISIS_MT_INFO_FIELDS;
};
static void *
lookup_mt_setting(struct list *mt_list, uint16_t mtid)
{
struct listnode *node;
struct mt_setting *setting;
for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting))
{
if (setting->mtid == mtid)
return setting;
}
return NULL;
}
static void
add_mt_setting(struct list **mt_list, void *setting)
{
if (!*mt_list)
*mt_list = list_new();
listnode_add(*mt_list, setting);
}
/* Area specific MT settings api */
struct isis_area_mt_setting*
area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
{
return lookup_mt_setting(area->mt_settings, mtid);
}
struct isis_area_mt_setting*
area_new_mt_setting(struct isis_area *area, uint16_t mtid)
{
struct isis_area_mt_setting *setting;
setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting));
setting->mtid = mtid;
return setting;
}
static void
area_free_mt_setting(void *setting)
{
XFREE(MTYPE_MT_AREA_SETTING, setting);
}
void
area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
{
add_mt_setting(&area->mt_settings, setting);
}
void
area_mt_init(struct isis_area *area)
{
struct isis_area_mt_setting *v4_unicast_setting;
/* MTID 0 is always enabled */
v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST);
v4_unicast_setting->enabled = true;
add_mt_setting(&area->mt_settings, v4_unicast_setting);
area->mt_settings->del = area_free_mt_setting;
}
void
area_mt_finish(struct isis_area *area)
{
list_delete(area->mt_settings);
area->mt_settings = NULL;
}
struct isis_area_mt_setting *
area_get_mt_setting(struct isis_area *area, uint16_t mtid)
{
struct isis_area_mt_setting *setting;
setting = area_lookup_mt_setting(area, mtid);
if (!setting)
{
setting = area_new_mt_setting(area, mtid);
area_add_mt_setting(area, setting);
}
return setting;
}
int
area_write_mt_settings(struct isis_area *area, struct vty *vty)
{
int written = 0;
struct listnode *node;
struct isis_area_mt_setting *setting;
for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
{
const char *name = isis_mtid2str(setting->mtid);
if (name && setting->enabled)
{
if (setting->mtid == ISIS_MT_IPV4_UNICAST)
continue; /* always enabled, no need to write out config */
vty_out (vty, " topology %s%s%s", name,
setting->overload ? " overload" : "",
VTY_NEWLINE);
written++;
}
}
return written;
}
bool area_is_mt(struct isis_area *area)
{
struct listnode *node, *node2;
struct isis_area_mt_setting *setting;
struct isis_circuit *circuit;
struct isis_circuit_mt_setting *csetting;
for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
{
if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
return true;
}
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
{
for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
{
if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
return true;
}
}
return false;
}
struct isis_area_mt_setting**
area_mt_settings(struct isis_area *area, unsigned int *mt_count)
{
static unsigned int size = 0;
static struct isis_area_mt_setting **rv = NULL;
unsigned int count = 0;
struct listnode *node;
struct isis_area_mt_setting *setting;
for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
{
if (!setting->enabled)
continue;
count++;
if (count > size)
{
rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
size = count;
}
rv[count-1] = setting;
}
*mt_count = count;
return rv;
}
/* Circuit specific MT settings api */
struct isis_circuit_mt_setting*
circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
{
return lookup_mt_setting(circuit->mt_settings, mtid);
}
struct isis_circuit_mt_setting*
circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
{
struct isis_circuit_mt_setting *setting;
setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
setting->mtid = mtid;
setting->enabled = true; /* Enabled is default for circuit */
return setting;
}
static void
circuit_free_mt_setting(void *setting)
{
XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
}
void
circuit_add_mt_setting(struct isis_circuit *circuit,
struct isis_circuit_mt_setting *setting)
{
add_mt_setting(&circuit->mt_settings, setting);
}
void
circuit_mt_init(struct isis_circuit *circuit)
{
circuit->mt_settings = list_new();
circuit->mt_settings->del = circuit_free_mt_setting;
}
void
circuit_mt_finish(struct isis_circuit *circuit)
{
list_delete(circuit->mt_settings);
circuit->mt_settings = NULL;
}
struct isis_circuit_mt_setting*
circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
{
struct isis_circuit_mt_setting *setting;
setting = circuit_lookup_mt_setting(circuit, mtid);
if (!setting)
{
setting = circuit_new_mt_setting(circuit, mtid);
circuit_add_mt_setting(circuit, setting);
}
return setting;
}
int
circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
{
int written = 0;
struct listnode *node;
struct isis_circuit_mt_setting *setting;
for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting))
{
const char *name = isis_mtid2str(setting->mtid);
if (name && !setting->enabled)
{
vty_out (vty, " no isis topology %s%s", name, VTY_NEWLINE);
written++;
}
}
return written;
}
struct isis_circuit_mt_setting**
circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
{
static unsigned int size = 0;
static struct isis_circuit_mt_setting **rv = NULL;
struct isis_area_mt_setting **area_settings;
unsigned int area_count;
unsigned int count = 0;
struct listnode *node;
struct isis_circuit_mt_setting *setting;
area_settings = area_mt_settings(circuit->area, &area_count);
for (unsigned int i = 0; i < area_count; i++)
{
for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
{
if (setting->mtid != area_settings[i]->mtid)
continue;
break;
}
if (!setting)
setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
if (!setting->enabled)
continue;
count++;
if (count > size)
{
rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
size = count;
}
rv[count-1] = setting;
}
*mt_count = count;
return rv;
}
/* ADJ specific MT API */
static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
uint16_t mtid)
{
if (adj->mt_count < index + 1)
{
adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
(index + 1) * sizeof(*adj->mt_set));
adj->mt_count = index + 1;
}
adj->mt_set[index] = mtid;
}
bool
tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
struct isis_adjacency *adj)
{
struct isis_circuit_mt_setting **mt_settings;
unsigned int circuit_mt_count;
unsigned int intersect_count = 0;
uint16_t *old_mt_set = NULL;
unsigned int old_mt_count;
old_mt_count = adj->mt_count;
if (old_mt_count)
{
old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
}
mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
for (unsigned int i = 0; i < circuit_mt_count; i++)
{
if (!tlvs->mt_router_info)
{
/* Other end does not have MT enabled */
if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST)
adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
}
else
{
struct listnode *node;
struct mt_router_info *info;
for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
{
if (mt_settings[i]->mtid == info->mtid)
adj_mt_set(adj, intersect_count++, info->mtid);
}
}
}
adj->mt_count = intersect_count;
bool changed = false;
if (adj->mt_count != old_mt_count)
changed = true;
if (!changed && old_mt_count
&& memcmp(adj->mt_set, old_mt_set,
old_mt_count * sizeof(*old_mt_set)))
changed = true;
if (old_mt_count)
XFREE(MTYPE_TMP, old_mt_set);
return changed;
}
bool
adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
{
for (unsigned int i = 0; i < adj->mt_count; i++)
if (adj->mt_set[i] == mtid)
return true;
return false;
}
void
adj_mt_finish(struct isis_adjacency *adj)
{
XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
adj->mt_count = 0;
}
/* TLV Router info api */
struct mt_router_info*
tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
{
return lookup_mt_setting(tlvs->mt_router_info, mtid);
}
/* TLV MT Neighbors api */
struct tlv_mt_neighbors*
tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
{
return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
}
static struct tlv_mt_neighbors*
tlvs_new_mt_neighbors(uint16_t mtid)
{
struct tlv_mt_neighbors *rv;
rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
rv->mtid = mtid;
rv->list = list_new();
return rv;
};
static void
tlvs_free_mt_neighbors(void *arg)
{
struct tlv_mt_neighbors *neighbors = arg;
if (neighbors && neighbors->list)
list_delete(neighbors->list);
XFREE(MTYPE_MT_NEIGHBORS, neighbors);
}
static void
tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
{
add_mt_setting(&tlvs->mt_is_neighs, neighbors);
tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
}
struct tlv_mt_neighbors*
tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
{
struct tlv_mt_neighbors *neighbors;
neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
if (!neighbors)
{
neighbors = tlvs_new_mt_neighbors(mtid);
tlvs_add_mt_neighbors(tlvs, neighbors);
}
return neighbors;
}
/* TLV MT IPv4 reach api */
struct tlv_mt_ipv4_reachs*
tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
{
return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
}
static struct tlv_mt_ipv4_reachs*
tlvs_new_mt_ipv4_reachs(uint16_t mtid)
{
struct tlv_mt_ipv4_reachs *rv;
rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
rv->mtid = mtid;
rv->list = list_new();
return rv;
};
static void
tlvs_free_mt_ipv4_reachs(void *arg)
{
struct tlv_mt_ipv4_reachs *reachs = arg;
if (reachs && reachs->list)
list_delete(reachs->list);
XFREE(MTYPE_MT_IPV4_REACHS, reachs);
}
static void
tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
{
add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
}
struct tlv_mt_ipv4_reachs*
tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
{
struct tlv_mt_ipv4_reachs *reachs;
reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
if (!reachs)
{
reachs = tlvs_new_mt_ipv4_reachs(mtid);
tlvs_add_mt_ipv4_reachs(tlvs, reachs);
}
return reachs;
}
/* TLV MT IPv6 reach api */
struct tlv_mt_ipv6_reachs*
tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
{
return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
}
static struct tlv_mt_ipv6_reachs*
tlvs_new_mt_ipv6_reachs(uint16_t mtid)
{
struct tlv_mt_ipv6_reachs *rv;
rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
rv->mtid = mtid;
rv->list = list_new();
return rv;
};
static void
tlvs_free_mt_ipv6_reachs(void *arg)
{
struct tlv_mt_ipv6_reachs *reachs = arg;
if (reachs && reachs->list)
list_delete(reachs->list);
XFREE(MTYPE_MT_IPV6_REACHS, reachs);
}
static void
tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
{
add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
}
struct tlv_mt_ipv6_reachs*
tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
{
struct tlv_mt_ipv6_reachs *reachs;
reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
if (!reachs)
{
reachs = tlvs_new_mt_ipv6_reachs(mtid);
tlvs_add_mt_ipv6_reachs(tlvs, reachs);
}
return reachs;
}
static void
mt_set_add(uint16_t **mt_set, unsigned int *size,
unsigned int *index, uint16_t mtid)
{
for (unsigned int i = 0; i < *index; i++)
{
if ((*mt_set)[i] == mtid)
return;
}
if (*index >= *size)
{
*mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
*size = (*index) + 1;
}
(*mt_set)[*index] = mtid;
*index = (*index) + 1;
}
static uint16_t *
circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
unsigned int *mt_count)
{
static uint16_t *rv;
static unsigned int size;
struct listnode *node;
struct isis_adjacency *adj;
unsigned int count = 0;
if (circuit->circ_type != CIRCUIT_T_BROADCAST)
{
*mt_count = 0;
return NULL;
}
for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
{
if (adj->adj_state != ISIS_ADJ_UP)
continue;
for (unsigned int i = 0; i < adj->mt_count; i++)
mt_set_add(&rv, &size, &count, adj->mt_set[i]);
}
*mt_count = count;
return rv;
}
static void
tlvs_add_mt_set(struct isis_area *area,
struct tlvs *tlvs, unsigned int mt_count,
uint16_t *mt_set, struct te_is_neigh *neigh)
{
for (unsigned int i = 0; i < mt_count; i++)
{
uint16_t mtid = mt_set[i];
struct te_is_neigh *ne_copy;
ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
memcpy(ne_copy, neigh, sizeof(*ne_copy));
if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
{
listnode_add(tlvs->te_is_neighs, ne_copy);
lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
area->area_tag, sysid_print(ne_copy->neigh_id),
LSP_PSEUDO_ID(ne_copy->neigh_id));
}
else
{
struct tlv_mt_neighbors *neighbors;
neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
neighbors->list->del = free_tlv;
listnode_add(neighbors->list, ne_copy);
lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
area->area_tag, sysid_print(ne_copy->neigh_id),
LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
}
}
}
void
tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
int level, struct te_is_neigh *neigh)
{
unsigned int mt_count;
uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
&mt_count);
tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
}
void
tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
struct te_is_neigh *neigh)
{
struct isis_adjacency *adj = circuit->u.p2p.neighbor;
tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
}

146
isisd/isis_mt.h Normal file
View File

@ -0,0 +1,146 @@
/*
* IS-IS Rout(e)ing protocol - Multi Topology Support
*
* Copyright (C) 2017 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
* FRR 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.
*
* FRR 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 FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef ISIS_MT_H
#define ISIS_MT_H
#define ISIS_MT_MASK 0x0fff
#define ISIS_MT_OL_MASK 0x8000
#define ISIS_MT_IPV4_UNICAST 0
#define ISIS_MT_IPV4_MGMT 1
#define ISIS_MT_IPV6_UNICAST 2
#define ISIS_MT_IPV4_MULTICAST 3
#define ISIS_MT_IPV6_MULTICAST 4
#define ISIS_MT_IPV6_MGMT 5
#define ISIS_MT_NAMES \
"<ipv4-unicast" \
"|ipv4-mgmt" \
"|ipv6-unicast" \
"|ipv4-multicast" \
"|ipv6-multicast" \
"|ipv6-mgmt" \
">"
#define ISIS_MT_DESCRIPTIONS \
"IPv4 unicast topology\n" \
"IPv4 management topology\n" \
"IPv6 unicast topology\n" \
"IPv4 multicast topology\n" \
"IPv6 multicast topology\n" \
"IPv6 management topology\n"
#define ISIS_MT_INFO_FIELDS \
uint16_t mtid;
struct list;
struct isis_area_mt_setting {
ISIS_MT_INFO_FIELDS
bool enabled;
bool overload;
};
struct isis_circuit_mt_setting {
ISIS_MT_INFO_FIELDS
bool enabled;
};
struct tlv_mt_neighbors {
ISIS_MT_INFO_FIELDS
struct list *list;
};
struct tlv_mt_ipv4_reachs {
ISIS_MT_INFO_FIELDS
struct list *list;
};
struct tlv_mt_ipv6_reachs {
ISIS_MT_INFO_FIELDS
struct list *list;
};
const char *isis_mtid2str(uint16_t mtid);
uint16_t isis_str2mtid(const char *name);
struct isis_adjacency;
struct isis_area;
struct isis_circuit;
struct tlvs;
struct te_is_neigh;
uint16_t isis_area_ipv6_topology(struct isis_area *area);
struct mt_router_info* tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_ipv4_reachs* tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_ipv4_reachs* tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_ipv6_reachs* tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
struct tlv_mt_ipv6_reachs* tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
uint16_t mtid);
struct isis_area_mt_setting* area_new_mt_setting(struct isis_area *area,
uint16_t mtid);
void area_add_mt_setting(struct isis_area *area,
struct isis_area_mt_setting *setting);
void area_mt_init(struct isis_area *area);
void area_mt_finish(struct isis_area *area);
struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area,
uint16_t mtid);
int area_write_mt_settings(struct isis_area *area, struct vty *vty);
bool area_is_mt(struct isis_area *area);
struct isis_area_mt_setting** area_mt_settings(struct isis_area *area,
unsigned int *mt_count);
struct isis_circuit_mt_setting* circuit_lookup_mt_setting(
struct isis_circuit *circuit,
uint16_t mtid);
struct isis_circuit_mt_setting* circuit_new_mt_setting(
struct isis_circuit *circuit,
uint16_t mtid);
void circuit_add_mt_setting(struct isis_circuit *circuit,
struct isis_circuit_mt_setting *setting);
void circuit_mt_init(struct isis_circuit *circuit);
void circuit_mt_finish(struct isis_circuit *circuit);
struct isis_circuit_mt_setting* circuit_get_mt_setting(
struct isis_circuit *circuit,
uint16_t mtid);
int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,
unsigned int *mt_count);
bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
struct isis_adjacency *adj);
bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
void adj_mt_finish(struct isis_adjacency *adj);
void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
int level, struct te_is_neigh *neigh);
void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
struct te_is_neigh *neigh);
#endif

View File

@ -53,6 +53,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#define ISIS_MINIMUM_FIXED_HDR_LEN 15
#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
@ -471,6 +472,7 @@ process_p2p_hello (struct isis_circuit *circuit)
expected |= TLVFLAG_NLPID;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
expected |= TLVFLAG_MT_ROUTER_INFORMATION;
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
@ -633,6 +635,8 @@ process_p2p_hello (struct isis_circuit *circuit)
if (found & TLVFLAG_IPV6_ADDR)
tlvs_to_adj_ipv6_addrs (&tlvs, adj);
bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@ -869,6 +873,13 @@ process_p2p_hello (struct isis_circuit *circuit)
/* down - area mismatch */
isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
}
if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
{
lsp_regenerate_schedule(adj->circuit->area,
isis_adj_usage2levels(adj->adj_usage), 0);
}
/* 8.2.5.2 c) if the action was up - comparing circuit IDs */
/* FIXME - Missing parts */
@ -1021,6 +1032,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
expected |= TLVFLAG_NLPID;
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
expected |= TLVFLAG_MT_ROUTER_INFORMATION;
auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
@ -1223,6 +1235,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
adj->circuit_t = hdr.circuit_t;
bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@ -1266,6 +1280,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
"no LAN Neighbours TLV found");
}
if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
lsp_regenerate_schedule(adj->circuit->area, level, 0);
out:
if (isis->debugs & DEBUG_ADJ_PACKETS)
{
@ -2337,6 +2354,37 @@ send_hello (struct isis_circuit *circuit, int level)
if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
return ISIS_WARNING;
/*
* MT Supported TLV
*
* TLV gets included if no topology is enabled on the interface,
* if one topology other than #0 is enabled, or if multiple topologies
* are enabled.
*/
struct isis_circuit_mt_setting **mt_settings;
unsigned int mt_count;
mt_settings = circuit_mt_settings(circuit, &mt_count);
if ((mt_count == 0 && area_is_mt(circuit->area))
|| (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
|| (mt_count > 1))
{
struct list *mt_info = list_new();
mt_info->del = free_tlv;
for (unsigned int i = 0; i < mt_count; i++)
{
struct mt_router_info *info;
info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
info->mtid = mt_settings[i]->mtid;
/* overload info is not valid in IIH, so it's not included here */
listnode_add(mt_info, info);
}
tlv_add_mt_router_info (mt_info, circuit->snd_stream);
list_free(mt_info);
}
/* IPv6 Interface Address TLV */
if (circuit->ipv6_router && circuit->ipv6_link &&
listcount (circuit->ipv6_link) > 0)

View File

@ -371,7 +371,9 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
stream_set_getp (circuit->snd_stream, 0);
memset (&sa, 0, sizeof (struct sockaddr_ll));
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
sa.sll_protocol = htons(isis_ethertype(frame_size));
sa.sll_ifindex = circuit->interface->ifindex;
sa.sll_halen = ETH_ALEN;
/* RFC5309 section 4.1 recommends ALL_ISS */
@ -418,7 +420,6 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
stream_set_getp (circuit->snd_stream, 0);
memset (&sa, 0, sizeof (struct sockaddr_ll));
sa.sll_family = AF_PACKET;
sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
sa.sll_ifindex = circuit->interface->ifindex;
sa.sll_halen = ETH_ALEN;
if (level == 1)

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,10 @@ enum vertextype
VTYPE_IP6REACH_EXTERNAL
};
#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
#define VTYPE_ES(t) ((t) == VTYPE_ES)
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
/*
* Triple <N, d(N), {Adj(N)}>
*/
@ -66,12 +70,14 @@ struct isis_spftree
unsigned int runcount; /* number of runs since uptime */
time_t last_run_timestamp; /* last run timestamp for scheduling */
time_t last_run_duration; /* last run duration in msec */
uint16_t mtid;
int family;
int level;
};
struct isis_spftree * isis_spftree_new (struct isis_area *area);
void isis_spftree_del (struct isis_spftree *spftree);
void isis_spftree_adj_del (struct isis_spftree *spftree,
struct isis_adjacency *adj);
void spftree_area_init (struct isis_area *area);
void spftree_area_del (struct isis_area *area);
void spftree_area_adj_del (struct isis_area *area,

View File

@ -43,6 +43,7 @@
#include "isisd/isis_pdu.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
void
free_tlv (void *val)
@ -61,10 +62,14 @@ free_tlvs (struct tlvs *tlvs)
{
if (tlvs->area_addrs)
list_delete (tlvs->area_addrs);
if (tlvs->mt_router_info)
list_delete (tlvs->mt_router_info);
if (tlvs->is_neighs)
list_delete (tlvs->is_neighs);
if (tlvs->te_is_neighs)
list_delete (tlvs->te_is_neighs);
if (tlvs->mt_is_neighs)
list_delete (tlvs->mt_is_neighs);
if (tlvs->es_neighs)
list_delete (tlvs->es_neighs);
if (tlvs->lsp_entries)
@ -81,16 +86,293 @@ free_tlvs (struct tlvs *tlvs)
list_delete (tlvs->ipv4_ext_reachs);
if (tlvs->te_ipv4_reachs)
list_delete (tlvs->te_ipv4_reachs);
if (tlvs->mt_ipv4_reachs)
list_delete (tlvs->mt_ipv4_reachs);
if (tlvs->ipv6_addrs)
list_delete (tlvs->ipv6_addrs);
if (tlvs->ipv6_reachs)
list_delete (tlvs->ipv6_reachs);
if (tlvs->mt_ipv6_reachs)
list_delete (tlvs->mt_ipv6_reachs);
memset (tlvs, 0, sizeof (struct tlvs));
return;
}
static int
parse_mtid(uint16_t *mtid, bool read_mtid,
unsigned int *length, u_char **pnt)
{
if (!read_mtid)
{
*mtid = ISIS_MT_IPV4_UNICAST;
return ISIS_OK;
}
uint16_t mtid_buf;
if (*length < sizeof(mtid_buf))
{
zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
return ISIS_WARNING;
}
memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
*pnt += sizeof(mtid_buf);
*length -= sizeof(mtid_buf);
*mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
return ISIS_OK;
}
static int
parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
unsigned int length, u_char *pnt)
{
struct list *neigh_list;
uint16_t mtid;
int rv;
rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
if (rv != ISIS_OK)
return rv;
if (mtid == ISIS_MT_IPV4_UNICAST)
{
if (!tlvs->te_is_neighs)
{
tlvs->te_is_neighs = list_new();
tlvs->te_is_neighs->del = free_tlv;
}
neigh_list = tlvs->te_is_neighs;
}
else
{
struct tlv_mt_neighbors *neighbors;
neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
neighbors->list->del = free_tlv;
neigh_list = neighbors->list;
}
while (length >= IS_NEIGHBOURS_LEN)
{
struct te_is_neigh *neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
pnt += IS_NEIGHBOURS_LEN;
length -= IS_NEIGHBOURS_LEN;
if (neigh->sub_tlvs_length > length)
{
zlog_warn("ISIS-TLV: neighbor subtlv length exceeds TLV size");
XFREE(MTYPE_ISIS_TLV, neigh);
return ISIS_WARNING;
}
memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
pnt += neigh->sub_tlvs_length;
length -= neigh->sub_tlvs_length;
listnode_add(neigh_list, neigh);
}
if (length)
{
zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
return ISIS_WARNING;
}
return ISIS_OK;
}
static int
parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
unsigned int length, u_char *pnt)
{
struct list *reach_list;
uint16_t mtid;
int rv;
rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
if (rv != ISIS_OK)
return rv;
if (mtid == ISIS_MT_IPV4_UNICAST)
{
if (!tlvs->te_ipv4_reachs)
{
tlvs->te_ipv4_reachs = list_new();
tlvs->te_ipv4_reachs->del = free_tlv;
}
reach_list = tlvs->te_ipv4_reachs;
}
else
{
struct tlv_mt_ipv4_reachs *reachs;
reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
reachs->list->del = free_tlv;
reach_list = reachs->list;
}
while (length >= 5) /* Metric + Control */
{
struct te_ipv4_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
memcpy(reach, pnt, 5); /* Metric + Control */
pnt += 5;
length -= 5;
unsigned char prefixlen = reach->control & 0x3F;
if (prefixlen > IPV4_MAX_BITLEN)
{
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix length %d", prefixlen);
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
if (length < (unsigned int)PSIZE(prefixlen))
{
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
pnt += PSIZE(prefixlen);
length -= PSIZE(prefixlen);
if (reach->control & TE_IPV4_HAS_SUBTLV)
{
if (length < 1)
{
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
u_char subtlv_len = *pnt;
pnt++;
length--;
if (length < subtlv_len)
{
zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
/* Skip Sub-TLVs for now */
pnt += subtlv_len;
length -= subtlv_len;
}
listnode_add(reach_list, reach);
}
if (length)
{
zlog_warn("ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
return ISIS_WARNING;
}
return ISIS_OK;
}
static int
parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
unsigned int length, u_char *pnt)
{
struct list *reach_list;
uint16_t mtid;
int rv;
rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
if (rv != ISIS_OK)
return rv;
if (mtid == ISIS_MT_IPV4_UNICAST)
{
if (!tlvs->ipv6_reachs)
{
tlvs->ipv6_reachs = list_new();
tlvs->ipv6_reachs->del = free_tlv;
}
reach_list = tlvs->ipv6_reachs;
}
else
{
struct tlv_mt_ipv6_reachs *reachs;
reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
reachs->list->del = free_tlv;
reach_list = reachs->list;
}
while (length >= 6) /* Metric + Control + Prefixlen */
{
struct ipv6_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
pnt += 6;
length -= 6;
if (reach->prefix_len > IPV6_MAX_BITLEN)
{
zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix length %d", reach->prefix_len);
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
if (length < (unsigned int)PSIZE(reach->prefix_len))
{
zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
pnt += PSIZE(reach->prefix_len);
length -= PSIZE(reach->prefix_len);
if (reach->control_info & CTRL_INFO_SUBTLVS)
{
if (length < 1)
{
zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLV missing");
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
u_char subtlv_len = *pnt;
pnt++;
length--;
if (length < subtlv_len)
{
zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
XFREE(MTYPE_ISIS_TLV, reach);
return ISIS_WARNING;
}
/* Skip Sub-TLVs for now */
pnt += subtlv_len;
length -= subtlv_len;
}
listnode_add(reach_list, reach);
}
if (length)
{
zlog_warn("ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
return ISIS_WARNING;
}
return ISIS_OK;
}
/*
* Parses the tlvs found in the variant length part of the PDU.
* Caller tells with flags in "expected" which TLV's it is interested in.
@ -103,17 +385,13 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
struct lan_neigh *lan_nei;
struct area_addr *area_addr;
struct is_neigh *is_nei;
struct te_is_neigh *te_is_nei;
struct es_neigh *es_nei;
struct lsp_entry *lsp_entry;
struct in_addr *ipv4_addr;
struct ipv4_reachability *ipv4_reach;
struct te_ipv4_reachability *te_ipv4_reach;
struct in6_addr *ipv6_addr;
struct ipv6_reachability *ipv6_reach;
int prefix_octets;
int value_len, retval = ISIS_OK;
u_char *start = stream, *pnt = stream, *endpnt;
u_char *start = stream, *pnt = stream;
*found = 0;
memset (tlvs, 0, sizeof (struct tlvs));
@ -207,54 +485,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
break;
case TE_IS_NEIGHBOURS:
/* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Neighbour ID | 7
* +---------------------------------------------------------------+
* | TE Metric | 3
* +---------------------------------------------------------------+
* | SubTLVs Length | 1
* +---------------------------------------------------------------+
* : :
*/
*found |= TLVFLAG_TE_IS_NEIGHS;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
areatag, length);
#endif /* EXTREME_TLV_DEBUG */
if (TLVFLAG_TE_IS_NEIGHS & *expected)
{
while (length > value_len)
{
te_is_nei = (struct te_is_neigh *) pnt;
value_len += IS_NEIGHBOURS_LEN;
pnt += IS_NEIGHBOURS_LEN;
/* FIXME - subtlvs are handled here, for now we skip */
/* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
/* So, it must be copied in a new te_is_neigh structure */
/* rather than just initialize pointer to the original LSP PDU */
/* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
if (IS_MPLS_TE(isisMplsTE))
{
struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
memcpy(new->te_metric, te_is_nei->te_metric, 3);
new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
te_is_nei = new;
}
/* Skip SUB TLVs payload */
value_len += te_is_nei->sub_tlvs_length;
pnt += te_is_nei->sub_tlvs_length;
retval = parse_mt_is_neighs(tlvs, false, length, pnt);
pnt += length;
break;
if (!tlvs->te_is_neighs)
tlvs->te_is_neighs = list_new ();
listnode_add (tlvs->te_is_neighs, te_is_nei);
}
}
else
{
pnt += length;
}
case MT_IS_NEIGHBOURS:
*found |= TLVFLAG_TE_IS_NEIGHS;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): MT IS Neighbours length %d",
areatag, length);
#endif
if (TLVFLAG_TE_IS_NEIGHS & *expected)
retval = parse_mt_is_neighs(tlvs, true, length, pnt);
pnt += length;
break;
case ES_NEIGHBOURS:
@ -577,71 +826,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
break;
case TE_IPV4_REACHABILITY:
/* +-------+-------+-------+-------+-------+-------+-------+-------+
* | TE Metric | 4
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | U/D | sTLV? | Prefix Mask Len | 1
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Prefix | 0-4
* +---------------------------------------------------------------+
* | sub tlvs |
* +---------------------------------------------------------------+
* : :
*/
*found |= TLVFLAG_TE_IPV4_REACHABILITY;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
areatag, length);
areatag, length);
#endif /* EXTREME_TLV_DEBUG */
endpnt = pnt + length;
if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
{
while (length > value_len)
{
te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
{
zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
"ability prefix length %d", areatag,
te_ipv4_reach->control & 0x3F);
retval = ISIS_WARNING;
break;
}
if (!tlvs->te_ipv4_reachs)
tlvs->te_ipv4_reachs = list_new ();
listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
/* Metric + Control-Byte + Prefix */
unsigned int entry_len = 5 + PSIZE(te_ipv4_reach->control & 0x3F);
value_len += entry_len;
pnt += entry_len;
if (te_ipv4_reach->control & TE_IPV4_HAS_SUBTLV)
{
if (length <= value_len)
{
zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLV missing",
areatag);
retval = ISIS_WARNING;
break;
}
u_char subtlv_len = *pnt;
value_len += subtlv_len + 1;
pnt += subtlv_len + 1;
if (length < value_len)
{
zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLVs have oversize",
areatag);
retval = ISIS_WARNING;
break;
}
}
}
}
pnt = endpnt;
retval = parse_mt_ipv4_reachs(tlvs, false, length, pnt);
pnt += length;
break;
case MT_IPV4_REACHABILITY:
*found |= TLVFLAG_TE_IPV4_REACHABILITY;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): IPv4 MT Reachability length %d",
areatag, length);
#endif /* EXTREME_TLV_DEBUG */
if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
retval = parse_mt_ipv4_reachs(tlvs, true, length, pnt);
pnt += length;
break;
case IPV6_ADDR:
/* +-------+-------+-------+-------+-------+-------+-------+-------+
* + IP version 6 address + 16
@ -672,67 +875,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
break;
case IPV6_REACHABILITY:
/* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Default Metric | 4
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Control Informantion |
* +---------------------------------------------------------------+
* | IPv6 Prefix Length |--+
* +---------------------------------------------------------------+ |
* | IPv6 Prefix |<-+
* +---------------------------------------------------------------+
*/
*found |= TLVFLAG_IPV6_REACHABILITY;
endpnt = pnt + length;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
areatag, length);
#endif /* EXTREME_TLV_DEBUG */
if (*expected & TLVFLAG_IPV6_REACHABILITY)
{
while (length > value_len)
{
ipv6_reach = (struct ipv6_reachability *) pnt;
if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
{
zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
"ability prefix length %d", areatag,
ipv6_reach->prefix_len);
retval = ISIS_WARNING;
break;
}
prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
value_len += prefix_octets + 6;
pnt += prefix_octets + 6;
if (ipv6_reach->control_info & CTRL_INFO_SUBTLVS)
{
if (length <= value_len)
{
zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLV missing",
areatag);
retval = ISIS_WARNING;
break;
}
u_char subtlv_len = *pnt;
value_len += subtlv_len + 1;
pnt += subtlv_len + 1;
if (length < value_len)
{
zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLVs have oversize",
areatag);
retval = ISIS_WARNING;
break;
}
}
/* FIXME: sub-tlvs */
if (!tlvs->ipv6_reachs)
tlvs->ipv6_reachs = list_new ();
listnode_add (tlvs->ipv6_reachs, ipv6_reach);
}
}
pnt = endpnt;
retval = parse_mt_ipv6_reachs(tlvs, false, length, pnt);
pnt += length;
break;
case MT_IPV6_REACHABILITY:
*found |= TLVFLAG_IPV6_REACHABILITY;
#ifdef EXTREME_TLV_DEBUG
zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
areatag, length);
#endif /* EXTREME_TLV_DEBUG */
if (*expected & TLVFLAG_IPV6_REACHABILITY)
retval = parse_mt_ipv6_reachs(tlvs, true, length, pnt);
pnt += length;
break;
case WAY3_HELLO:
/* +---------------------------------------------------------------+
* | Adjacency state | 1
@ -786,6 +947,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
pnt += length;
break;
case MT_ROUTER_INFORMATION:
*found |= TLVFLAG_MT_ROUTER_INFORMATION;
if (*expected & TLVFLAG_MT_ROUTER_INFORMATION)
{
if (!tlvs->mt_router_info)
{
tlvs->mt_router_info = list_new();
tlvs->mt_router_info->del = free_tlv;
}
while (length > value_len)
{
uint16_t mt_info;
struct mt_router_info *info;
if (value_len + sizeof(mt_info) > length) {
zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag);
pnt += length - value_len;
break;
}
memcpy(&mt_info, pnt, sizeof(mt_info));
pnt += sizeof(mt_info);
value_len += sizeof(mt_info);
mt_info = ntohs(mt_info);
info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
info->mtid = mt_info & ISIS_MT_MASK;
info->overload = mt_info & ISIS_MT_OL_MASK;
listnode_add(tlvs->mt_router_info, info);
}
}
else
{
pnt += length;
}
break;
default:
zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
areatag, type, length);
@ -825,6 +1022,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
return ISIS_OK;
}
int
tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream)
{
struct listnode *node;
struct mt_router_info *info;
uint16_t value[127];
uint16_t *pos = value;
for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info))
{
uint16_t mt_info;
mt_info = info->mtid;
if (info->overload)
mt_info |= ISIS_MT_OL_MASK;
*pos = htons(mt_info);
pos++;
}
return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
(u_char*)value, stream);
}
int
tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
{
@ -887,26 +1109,44 @@ tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
}
int
tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
static size_t
max_tlv_size(struct stream *stream)
{
size_t avail = stream_get_size (stream) - stream_get_endp(stream);
if (avail < 2)
return 0;
if (avail < 257)
return avail - 2;
return 255;
}
unsigned int
tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg)
{
struct listnode *node;
struct te_is_neigh *te_is_neigh;
u_char value[255];
u_char *pos = value;
int retval;
uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
unsigned int consumed = 0;
size_t max_size = max_tlv_size(stream);
if (mtid != ISIS_MT_IPV4_UNICAST)
{
uint16_t mtid_conversion = ntohs(mtid);
memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
pos += sizeof(mtid_conversion);
}
for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
{
/* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
{
retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
if (retval != ISIS_OK)
return retval;
pos = value;
}
if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > max_size)
break;
memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
pos += ISIS_SYS_ID_LEN + 1;
memcpy (pos, te_is_neigh->te_metric, 3);
@ -920,9 +1160,17 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
pos += te_is_neigh->sub_tlvs_length;
}
consumed++;
}
return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
if (consumed)
{
int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IS_NEIGHBOURS
: TE_IS_NEIGHBOURS,
pos - value, value, stream);
assert(rv == ISIS_OK);
}
return consumed;
}
int
@ -1100,37 +1348,49 @@ tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
}
int
tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
unsigned int
tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg)
{
struct listnode *node;
struct te_ipv4_reachability *te_reach;
u_char value[255];
u_char *pos = value;
u_char prefix_size;
int retval;
uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
unsigned int consumed = 0;
size_t max_size = max_tlv_size(stream);
if (mtid != ISIS_MT_IPV4_UNICAST)
{
uint16_t mtid_conversion = ntohs(mtid);
memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
pos += sizeof(mtid_conversion);
}
for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
{
prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
unsigned char prefixlen = te_reach->control & 0x3F;
if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
break;
if (pos - value + (5 + prefix_size) > 255)
{
retval =
add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
if (retval != ISIS_OK)
return retval;
pos = value;
}
*(u_int32_t *) pos = te_reach->te_metric;
pos += 4;
*pos = te_reach->control;
pos++;
memcpy (pos, &te_reach->prefix_start, prefix_size);
pos += prefix_size;
memcpy (pos, &te_reach->prefix_start, PSIZE(prefixlen));
pos += PSIZE(prefixlen);
consumed++;
}
return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
if (consumed)
{
int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV4_REACHABILITY
: TE_IPV4_REACHABILITY,
pos - value, value, stream);
assert(rv == ISIS_OK);
}
return consumed;
}
int
@ -1158,36 +1418,49 @@ tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
return add_tlv (IPV6_ADDR, pos - value, value, stream);
}
int
tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
unsigned int
tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg)
{
struct listnode *node;
struct ipv6_reachability *ip6reach;
u_char value[255];
u_char *pos = value;
int retval, prefix_octets;
uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
unsigned int consumed = 0;
size_t max_size = max_tlv_size(stream);
if (mtid != ISIS_MT_IPV4_UNICAST)
{
uint16_t mtid_conversion = ntohs(mtid);
memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
pos += sizeof(mtid_conversion);
}
for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
{
if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
{
retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
if (retval != ISIS_OK)
return retval;
pos = value;
}
*(uint32_t *) pos = ip6reach->metric;
if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len) > max_size)
break;
*(uint32_t *)pos = ip6reach->metric;
pos += 4;
*pos = ip6reach->control_info;
pos++;
prefix_octets = ((ip6reach->prefix_len + 7) / 8);
*pos = ip6reach->prefix_len;
pos++;
memcpy (pos, ip6reach->prefix, prefix_octets);
pos += prefix_octets;
memcpy (pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
pos += PSIZE(ip6reach->prefix_len);
consumed++;
}
return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
if (consumed)
{
int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV6_REACHABILITY
: IPV6_REACHABILITY,
pos - value, value, stream);
assert(rv == ISIS_OK);
}
return consumed;
}
int

View File

@ -24,6 +24,8 @@
#ifndef _ZEBRA_ISIS_TLV_H
#define _ZEBRA_ISIS_TLV_H
#include "isisd/isis_mt.h"
/*
* The list of TLVs we (should) support.
* ____________________________________________________________________________
@ -109,8 +111,12 @@
#define TE_IPV4_REACHABILITY 135
#define DYNAMIC_HOSTNAME 137
#define GRACEFUL_RESTART 211
#define MT_IS_NEIGHBOURS 222
#define MT_ROUTER_INFORMATION 229
#define IPV6_ADDR 232
#define MT_IPV4_REACHABILITY 235
#define IPV6_REACHABILITY 236
#define MT_IPV6_REACHABILITY 237
#define WAY3_HELLO 240
#define ROUTER_INFORMATION 242
@ -250,6 +256,12 @@ struct ipv6_reachability
#define CTRL_INFO_SUBTLVS 0x20
struct mt_router_info
{
ISIS_MT_INFO_FIELDS
bool overload;
};
/*
* Pointer to each tlv type, filled by parse_tlvs()
*/
@ -260,8 +272,10 @@ struct tlvs
struct nlpids *nlpids;
struct te_router_id *router_id;
struct list *area_addrs;
struct list *mt_router_info;
struct list *is_neighs;
struct list *te_is_neighs;
struct list *mt_is_neighs;
struct list *es_neighs;
struct list *lsp_entries;
struct list *prefix_neighs;
@ -270,8 +284,10 @@ struct tlvs
struct list *ipv4_int_reachs;
struct list *ipv4_ext_reachs;
struct list *te_ipv4_reachs;
struct list *mt_ipv4_reachs;
struct list *ipv6_addrs;
struct list *ipv6_reachs;
struct list *mt_ipv6_reachs;
struct isis_passwd auth_info;
};
@ -301,6 +317,7 @@ struct tlvs
#define TLVFLAG_TE_ROUTER_ID (1<<19)
#define TLVFLAG_CHECKSUM (1<<20)
#define TLVFLAG_GRACEFUL_RESTART (1<<21)
#define TLVFLAG_MT_ROUTER_INFORMATION (1<<22)
void init_tlvs (struct tlvs *tlvs, uint32_t expected);
void free_tlvs (struct tlvs *tlvs);
@ -310,9 +327,10 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
int add_tlv (u_char, u_char, u_char *, struct stream *);
void free_tlv (void *val);
int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream);
int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);
unsigned int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg);
int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream);
int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
int tlv_add_checksum (struct checksum *checksum, struct stream *stream);
@ -325,9 +343,9 @@ int tlv_add_dynamic_hostname (struct hostname *hostname,
int tlv_add_lsp_entries (struct list *lsps, struct stream *stream);
int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream);
int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream);
int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream);
unsigned int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg);
int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream);
int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream);
unsigned int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg);
int tlv_add_padding (struct stream *stream);

View File

@ -29,6 +29,7 @@
#include "isis_circuit.h"
#include "isis_csm.h"
#include "isis_misc.h"
#include "isis_mt.h"
#include "isisd.h"
static struct isis_circuit *
@ -1271,6 +1272,48 @@ DEFUN (no_psnp_interval_l2,
return CMD_SUCCESS;
}
DEFUN (circuit_topology,
circuit_topology_cmd,
"isis topology " ISIS_MT_NAMES,
"IS-IS commands\n"
"Configure interface IS-IS topologies\n"
ISIS_MT_DESCRIPTIONS)
{
struct isis_circuit *circuit = isis_circuit_lookup (vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
const char *arg = argv[2]->arg;
uint16_t mtid = isis_str2mtid(arg);
if (mtid == (uint16_t)-1)
{
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
return isis_circuit_mt_enabled_set(circuit, mtid, true);
}
DEFUN (no_circuit_topology,
no_circuit_topology_cmd,
"no isis topology " ISIS_MT_NAMES,
NO_STR
"IS-IS commands\n"
"Configure interface IS-IS topologies\n"
ISIS_MT_DESCRIPTIONS)
{
struct isis_circuit *circuit = isis_circuit_lookup (vty);
if (!circuit)
return CMD_ERR_NO_MATCH;
const char *arg = argv[3]->arg;
uint16_t mtid = isis_str2mtid(arg);
if (mtid == (uint16_t)-1)
{
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
return isis_circuit_mt_enabled_set(circuit, mtid, false);
}
static int
validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
@ -2116,6 +2159,9 @@ isis_vty_init (void)
install_element (INTERFACE_NODE, &psnp_interval_l2_cmd);
install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd);
install_element (INTERFACE_NODE, &circuit_topology_cmd);
install_element (INTERFACE_NODE, &no_circuit_topology_cmd);
install_element (ISIS_NODE, &metric_style_cmd);
install_element (ISIS_NODE, &no_metric_style_cmd);

View File

@ -56,6 +56,7 @@
#include "isisd/isis_zebra.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
struct isis *isis = NULL;
@ -156,6 +157,8 @@ isis_area_create (const char *area_tag)
area->lsp_frag_threshold = 90;
area->lsp_mtu = DEFAULT_LSP_MTU;
area_mt_init(area);
area->area_tag = strdup (area_tag);
listnode_add (isis->area_list, area);
area->isis = isis;
@ -296,6 +299,8 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
free (area->area_tag);
area_mt_finish(area);
XFREE (MTYPE_ISIS_AREA, area);
if (listcount (isis->area_list) == 0)
@ -307,6 +312,33 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
return CMD_SUCCESS;
}
static void
area_set_mt_enabled(struct isis_area *area, uint16_t mtid, bool enabled)
{
struct isis_area_mt_setting *setting;
setting = area_get_mt_setting(area, mtid);
if (setting->enabled != enabled)
{
setting->enabled = enabled;
lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
}
}
static void
area_set_mt_overload(struct isis_area *area, uint16_t mtid, bool overload)
{
struct isis_area_mt_setting *setting;
setting = area_get_mt_setting(area, mtid);
if (setting->overload != overload)
{
setting->overload = overload;
if (setting->enabled)
lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
}
}
int
area_net_title (struct vty *vty, const char *net_title)
{
@ -1626,6 +1658,61 @@ DEFUN (no_net,
return area_clear_net_title (vty, argv[idx_word]->arg);
}
DEFUN (isis_topology,
isis_topology_cmd,
"topology " ISIS_MT_NAMES " [overload]",
"Configure IS-IS topologies\n"
ISIS_MT_DESCRIPTIONS
"Set overload bit for topology\n")
{
VTY_DECLVAR_CONTEXT (isis_area, area);
const char *arg = argv[1]->arg;
uint16_t mtid = isis_str2mtid(arg);
if (mtid == (uint16_t)-1)
{
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
if (mtid == ISIS_MT_IPV4_UNICAST)
{
vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
area_set_mt_enabled(area, mtid, true);
area_set_mt_overload(area, mtid, (argc == 3));
return CMD_SUCCESS;
}
DEFUN (no_isis_topology,
no_isis_topology_cmd,
"no topology " ISIS_MT_NAMES " [overload]",
NO_STR
"Configure IS-IS topologies\n"
ISIS_MT_DESCRIPTIONS
"Set overload bit for topology\n")
{
VTY_DECLVAR_CONTEXT (isis_area, area);
const char *arg = argv[2]->arg;
uint16_t mtid = isis_str2mtid(arg);
if (mtid == (uint16_t)-1)
{
vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
if (mtid == ISIS_MT_IPV4_UNICAST)
{
vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
return CMD_ERR_AMBIGUOUS;
}
area_set_mt_enabled(area, mtid, false);
area_set_mt_overload(area, mtid, false);
return CMD_SUCCESS;
}
void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu)
{
area->lsp_mtu = lsp_mtu;
@ -2148,6 +2235,7 @@ isis_config_write (struct vty *vty)
write++;
}
write += area_write_mt_settings(area, vty);
}
isis_mpls_te_config_write_router(vty);
}
@ -2254,6 +2342,9 @@ isis_init ()
install_element (ISIS_NODE, &net_cmd);
install_element (ISIS_NODE, &no_net_cmd);
install_element (ISIS_NODE, &isis_topology_cmd);
install_element (ISIS_NODE, &no_isis_topology_cmd);
install_element (ISIS_NODE, &log_adj_changes_cmd);
install_element (ISIS_NODE, &no_log_adj_changes_cmd);

View File

@ -120,6 +120,8 @@ struct isis_area
int ip_circuits;
/* logging adjacency changes? */
u_char log_adj_changes;
/* multi topology settings */
struct list *mt_settings;
int ipv6_circuits;
/* Counters */
u_int32_t circuit_state_changes;

View File

@ -80,10 +80,6 @@ static zebra_capabilities_t _caps_p [] =
static struct zebra_privs_t lde_privs =
{
#if defined(FRR_USER) && defined(FRR_GROUP)
.user = FRR_USER,
.group = FRR_GROUP,
#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
@ -164,10 +160,8 @@ void
lde_init(struct ldpd_init *init)
{
/* drop privileges */
if (init->user)
lde_privs.user = init->user;
if (init->group)
lde_privs.group = init->group;
lde_privs.user = init->user;
lde_privs.group = init->group;
zprivs_init(&lde_privs);
#ifdef HAVE_PLEDGE

View File

@ -66,10 +66,6 @@ static zebra_capabilities_t _caps_p [] =
struct zebra_privs_t ldpe_privs =
{
#if defined(FRR_USER) && defined(FRR_GROUP)
.user = FRR_USER,
.group = FRR_GROUP,
#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
@ -143,10 +139,8 @@ void
ldpe_init(struct ldpd_init *init)
{
/* drop privileges */
if (init->user)
ldpe_privs.user = init->user;
if (init->group)
ldpe_privs.group = init->group;
ldpe_privs.user = init->user;
ldpe_privs.group = init->group;
zprivs_init(&ldpe_privs);
/* listen on ldpd control socket */

View File

@ -35,6 +35,7 @@ libfrr_la_SOURCES = \
sha256.c \
module.c \
hook.c \
frr_pthread.c \
# end
BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
@ -76,6 +77,7 @@ pkginclude_HEADERS = \
hook.h \
libfrr.h \
sha256.h \
frr_pthread.h \
# end
noinst_HEADERS = \

View File

@ -1055,9 +1055,11 @@ node_parent ( enum node_type node )
case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
case BGP_IPV6L_NODE:
ret = BGP_NODE;
break;
case KEYCHAIN_KEY_NODE:
@ -1415,6 +1417,7 @@ cmd_exit (struct vty *vty)
break;
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV4L_NODE:
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
@ -1426,6 +1429,7 @@ cmd_exit (struct vty *vty)
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
case BGP_IPV6L_NODE:
vty->node = BGP_NODE;
break;
case LDP_IPV4_NODE:
@ -1493,9 +1497,11 @@ DEFUN (config_end,
case BGP_VPNV6_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
case BGP_IPV6L_NODE:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:

View File

@ -97,8 +97,10 @@ enum node_type
BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */
BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */
BGP_IPV4L_NODE, /* BGP IPv4 labeled unicast address family. */
BGP_IPV6_NODE, /* BGP IPv6 address family */
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
BGP_IPV6L_NODE, /* BGP IPv6 labeled unicast address family. */
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
BGP_VRF_POLICY_NODE, /* BGP VRF policy */

184
lib/frr_pthread.c Normal file
View File

@ -0,0 +1,184 @@
/*
Utilities and interfaces for managing POSIX threads
Copyright (C) 2017 Cumulus Networks
This program 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 of the License, or
(at your option) any later version.
This program 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 this program; see the file COPYING; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301 USA
*/
#include <zebra.h>
#include <pthread.h>
#include "frr_pthread.h"
#include "memory.h"
#include "hash.h"
DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
static unsigned int next_id = 0;
/* Hash table of all frr_pthreads along with synchronization primitive(s) and
* hash table callbacks.
* ------------------------------------------------------------------------ */
static struct hash *pthread_table;
static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
/* pthread_table->hash_cmp */
static int pthread_table_hash_cmp(const void *value1, const void *value2)
{
const struct frr_pthread *tq1 = value1;
const struct frr_pthread *tq2 = value2;
return (tq1->id == tq2->id);
}
/* pthread_table->hash_key */
static unsigned int pthread_table_hash_key(void *value)
{
return ((struct frr_pthread *)value)->id;
}
/* ------------------------------------------------------------------------ */
void frr_pthread_init()
{
pthread_mutex_lock(&pthread_table_mtx);
{
pthread_table =
hash_create(pthread_table_hash_key, pthread_table_hash_cmp);
}
pthread_mutex_unlock(&pthread_table_mtx);
}
void frr_pthread_finish()
{
pthread_mutex_lock(&pthread_table_mtx);
{
hash_clean(pthread_table, (void (*)(void *))frr_pthread_destroy);
hash_free(pthread_table);
}
pthread_mutex_unlock(&pthread_table_mtx);
}
struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
void *(*start_routine) (void *),
int (*stop_routine) (void **, struct frr_pthread *))
{
static struct frr_pthread holder = { 0 };
struct frr_pthread *fpt = NULL;
pthread_mutex_lock(&pthread_table_mtx);
{
holder.id = id;
if (!hash_lookup(pthread_table, &holder)) {
struct frr_pthread *fpt =
XCALLOC(MTYPE_FRR_PTHREAD,
sizeof(struct frr_pthread));
fpt->id = id;
fpt->master = thread_master_create();
fpt->start_routine = start_routine;
fpt->stop_routine = stop_routine;
fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
hash_get(pthread_table, fpt, hash_alloc_intern);
}
}
pthread_mutex_unlock(&pthread_table_mtx);
return fpt;
}
void frr_pthread_destroy(struct frr_pthread *fpt)
{
thread_master_free(fpt->master);
XFREE(MTYPE_FRR_PTHREAD, fpt->name);
XFREE(MTYPE_FRR_PTHREAD, fpt);
}
struct frr_pthread *frr_pthread_get(unsigned int id)
{
static struct frr_pthread holder = { 0 };
struct frr_pthread *fpt;
pthread_mutex_lock(&pthread_table_mtx);
{
holder.id = id;
fpt = hash_lookup(pthread_table, &holder);
}
pthread_mutex_unlock(&pthread_table_mtx);
return fpt;
}
int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg)
{
struct frr_pthread *fpt = frr_pthread_get(id);
int ret;
if (!fpt)
return -1;
ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
/* Per pthread_create(3), the contents of fpt->thread are undefined if
* pthread_create() did not succeed. Reset this value to zero. */
if (ret < 0)
memset(&fpt->thread, 0x00, sizeof(fpt->thread));
return ret;
}
/**
* Calls the stop routine for the frr_pthread and resets any relevant fields.
*
* @param fpt - the frr_pthread to stop
* @param result - pointer to result pointer
* @return the return code from the stop routine
*/
static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
{
int ret = (*fpt->stop_routine) (result, fpt);
memset(&fpt->thread, 0x00, sizeof(fpt->thread));
return ret;
}
int frr_pthread_stop(unsigned int id, void **result)
{
struct frr_pthread *fpt = frr_pthread_get(id);
return frr_pthread_stop_actual(fpt, result);
}
/**
* Callback for hash_iterate to stop all frr_pthread's.
*/
static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
{
struct frr_pthread *fpt = hb->data;
frr_pthread_stop_actual(fpt, NULL);
}
void frr_pthread_stop_all()
{
pthread_mutex_lock(&pthread_table_mtx);
{
hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
}
pthread_mutex_unlock(&pthread_table_mtx);
}
unsigned int frr_pthread_get_id()
{
return next_id++;
}

145
lib/frr_pthread.h Normal file
View File

@ -0,0 +1,145 @@
/*
Utilities and interfaces for managing POSIX threads
Copyright (C) 2017 Cumulus Networks
This program 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 of the License, or
(at your option) any later version.
This program 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 this program; see the file COPYING; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301 USA
*/
#ifndef _FRR_PTHREAD_H
#define _FRR_PTHREAD_H
#include <pthread.h>
#include "thread.h"
struct frr_pthread {
/* pthread id */
pthread_t thread;
/* frr thread identifier */
unsigned int id;
/* thread master for this pthread's thread.c event loop */
struct thread_master *master;
/* start routine */
void *(*start_routine) (void *);
/* stop routine */
int (*stop_routine) (void **, struct frr_pthread *);
/* the (hopefully descriptive) name of this thread */
char *name;
};
/* Initializes this module.
*
* Must be called before using any of the other functions.
*/
void frr_pthread_init(void);
/* Uninitializes this module.
*
* Destroys all registered frr_pthread's and internal data structures.
*
* It is safe to call frr_pthread_init() after this function to reinitialize
* the module.
*/
void frr_pthread_finish(void);
/* Creates a new frr_pthread.
*
* If the provided ID is already assigned to an existing frr_pthread, the
* return value will be NULL.
*
* @param name - the name of the thread. Doesn't have to be unique, but it
* probably should be. This value is copied and may be safely free'd upon
* return.
*
* @param id - the integral ID of the thread. MUST be unique. The caller may
* use this id to retrieve the thread.
*
* @param start_routine - start routine for the pthread, will be passed to
* pthread_create (see those docs for details)
*
* @param stop_routine - stop routine for the pthread, called to terminate the
* thread. This function should gracefully stop the pthread and clean up any
* thread-specific resources. The passed pointer is used to return a data
* result.
*
* @return the created frr_pthread upon success, or NULL upon failure
*/
struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
void *(*start_routine) (void *),
int (*stop_routine) (void **, struct frr_pthread *));
/* Destroys an frr_pthread.
*
* Assumes that the associated pthread, if any, has already terminated.
*
* @param fpt - the frr_pthread to destroy
*/
void frr_pthread_destroy(struct frr_pthread *fpt);
/* Gets an existing frr_pthread by its id.
*
* @return frr_thread associated with the provided id, or NULL on error
*/
struct frr_pthread *frr_pthread_get(unsigned int id);
/* Creates a new pthread and binds it to a frr_pthread.
*
* This function is a wrapper for pthread_create. The first parameter is the
* frr_pthread to bind the created pthread to. All subsequent arguments are
* passed unmodified to pthread_create().
*
* This function returns the same code as pthread_create(). If the value is
* zero, the provided frr_pthread is bound to a running POSIX thread. If the
* value is less than zero, the provided frr_pthread is guaranteed to be a
* clean instance that may be susbsequently passed to frr_pthread_run().
*
* @param id - frr_pthread to bind the created pthread to
* @param attr - see pthread_create(3)
* @param arg - see pthread_create(3)
*
* @return see pthread_create(3)
*/
int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg);
/* Stops an frr_pthread with a result.
*
* @param id - frr_pthread to stop
* @param result - where to store the thread's result, if any. May be NULL if a
* result is not needed.
*/
int frr_pthread_stop(unsigned int id, void **result);
/* Stops all frr_pthread's. */
void frr_pthread_stop_all(void);
/* Returns a unique identifier for use with frr_pthread_new().
*
* Internally, this is an integer that increments after each call to this
* function. Because the number of pthreads created should never exceed INT_MAX
* during the life of the program, there is no overflow protection. If by
* chance this function returns an ID which is already in use,
* frr_pthread_new() will fail when it is provided.
*
* @return unique identifier
*/
unsigned int frr_pthread_get_id(void);
#endif /* _FRR_PTHREAD_H */

View File

@ -85,7 +85,8 @@ enum lsp_types_t
{
ZEBRA_LSP_NONE = 0, /* No LSP. */
ZEBRA_LSP_STATIC = 1, /* Static LSP. */
ZEBRA_LSP_LDP = 2 /* LDP LSP. */
ZEBRA_LSP_LDP = 2, /* LDP LSP. */
ZEBRA_LSP_BGP = 3 /* BGP LSP. */
};
/* Functions for basic label operations. */
@ -122,6 +123,11 @@ mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label,
*ttl = MPLS_LABEL_TTL(local_lse);
}
/* Invalid label index value (when used with BGP Prefix-SID). Should
* match the BGP definition.
*/
#define MPLS_INVALID_LABEL_INDEX 0xFFFFFFFF
/* Printable string for labels (with consideration for reserved values). */
static inline char *

View File

@ -92,6 +92,28 @@ nexthop_type_to_str (enum nexthop_types_t nh_type)
return desc[nh_type];
}
/*
* Check if the labels match for the 2 nexthops specified.
*/
int
nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2)
{
struct nexthop_label *nhl1, *nhl2;
nhl1 = nh1->nh_label;
nhl2 = nh2->nh_label;
if ((nhl1 && !nhl2) || (!nhl1 && nhl2))
return 0;
if (nhl1->num_labels != nhl2->num_labels)
return 0;
if (memcmp (nhl1->label, nhl2->label, nhl1->num_labels))
return 0;
return 1;
}
struct nexthop *
nexthop_new (void)
{

View File

@ -117,6 +117,7 @@ void nexthop_del_labels (struct nexthop *);
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
extern int nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2);
extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size);
#endif /*_LIB_NEXTHOP_H */

View File

@ -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)

View File

@ -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

View File

@ -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 *);

View File

@ -41,7 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
#include <mach/mach_time.h>
#endif
/* Relative time, since startup */
static pthread_mutex_t cpu_record_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct hash *cpu_record = NULL;
static unsigned long
@ -137,9 +137,14 @@ cpu_record_print(struct vty *vty, thread_type filter)
vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
vty_out(vty, " Avg uSec Max uSecs");
vty_out(vty, " Type Thread%s", VTY_NEWLINE);
hash_iterate(cpu_record,
(void(*)(struct hash_backet*,void*))cpu_record_hash_print,
args);
pthread_mutex_lock (&cpu_record_mtx);
{
hash_iterate(cpu_record,
(void(*)(struct hash_backet*,void*))cpu_record_hash_print,
args);
}
pthread_mutex_unlock (&cpu_record_mtx);
if (tmp.total_calls > 0)
vty_out_cpu_thread_history(vty, &tmp);
@ -216,16 +221,25 @@ cpu_record_hash_clear (struct hash_backet *bucket,
if ( !(a->types & *filter) )
return;
hash_release (cpu_record, bucket->data);
pthread_mutex_lock (&cpu_record_mtx);
{
hash_release (cpu_record, bucket->data);
}
pthread_mutex_unlock (&cpu_record_mtx);
}
static void
cpu_record_clear (thread_type filter)
{
thread_type *tmp = &filter;
hash_iterate (cpu_record,
(void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
tmp);
pthread_mutex_lock (&cpu_record_mtx);
{
hash_iterate (cpu_record,
(void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
tmp);
}
pthread_mutex_unlock (&cpu_record_mtx);
}
DEFUN (clear_thread_cpu,
@ -326,16 +340,20 @@ thread_master_create (void)
getrlimit(RLIMIT_NOFILE, &limit);
if (cpu_record == NULL)
cpu_record
= hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
(int (*) (const void *, const void *))cpu_record_hash_cmp);
pthread_mutex_lock (&cpu_record_mtx);
{
if (cpu_record == NULL)
cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
(int (*) (const void *, const void *))
cpu_record_hash_cmp);
}
pthread_mutex_unlock (&cpu_record_mtx);
rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
if (rv == NULL)
{
return NULL;
}
return NULL;
pthread_mutex_init (&rv->mtx, NULL);
rv->fd_limit = (int)limit.rlim_cur;
rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
@ -358,6 +376,8 @@ thread_master_create (void)
rv->background = pqueue_create();
rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
rv->timer->update = rv->background->update = thread_timer_update;
rv->spin = true;
rv->handle_signals = true;
#if defined(HAVE_POLL)
rv->handler.pfdsize = rv->fd_limit;
@ -498,11 +518,16 @@ thread_queue_free (struct thread_master *m, struct pqueue *queue)
void
thread_master_free_unused (struct thread_master *m)
{
struct thread *t;
while ((t = thread_trim_head(&m->unuse)) != NULL)
{
XFREE(MTYPE_THREAD, t);
}
pthread_mutex_lock (&m->mtx);
{
struct thread *t;
while ((t = thread_trim_head(&m->unuse)) != NULL)
{
pthread_mutex_destroy (&t->mtx);
XFREE(MTYPE_THREAD, t);
}
}
pthread_mutex_unlock (&m->mtx);
}
/* Stop thread scheduler. */
@ -516,25 +541,37 @@ thread_master_free (struct thread_master *m)
thread_list_free (m, &m->ready);
thread_list_free (m, &m->unuse);
thread_queue_free (m, m->background);
pthread_mutex_destroy (&m->mtx);
#if defined(HAVE_POLL)
XFREE (MTYPE_THREAD_MASTER, m->handler.pfds);
#endif
XFREE (MTYPE_THREAD_MASTER, m);
if (cpu_record)
{
hash_clean (cpu_record, cpu_record_hash_free);
hash_free (cpu_record);
cpu_record = NULL;
}
pthread_mutex_lock (&cpu_record_mtx);
{
if (cpu_record)
{
hash_clean (cpu_record, cpu_record_hash_free);
hash_free (cpu_record);
cpu_record = NULL;
}
}
pthread_mutex_unlock (&cpu_record_mtx);
}
/* Return remain time in second. */
unsigned long
thread_timer_remain_second (struct thread *thread)
{
int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
int64_t remain;
pthread_mutex_lock (&thread->mtx);
{
remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
}
pthread_mutex_unlock (&thread->mtx);
return remain < 0 ? 0 : remain;
}
@ -545,7 +582,11 @@ struct timeval
thread_timer_remain(struct thread *thread)
{
struct timeval remain;
monotime_until(&thread->u.sands, &remain);
pthread_mutex_lock (&thread->mtx);
{
monotime_until(&thread->u.sands, &remain);
}
pthread_mutex_unlock (&thread->mtx);
return remain;
}
@ -560,8 +601,11 @@ thread_get (struct thread_master *m, u_char type,
if (! thread)
{
thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
/* mutex only needs to be initialized at struct creation. */
pthread_mutex_init (&thread->mtx, NULL);
m->alloc++;
}
thread->type = type;
thread->add_type = type;
thread->master = m;
@ -584,8 +628,12 @@ thread_get (struct thread_master *m, u_char type,
{
tmp.func = func;
tmp.funcname = funcname;
thread->hist = hash_get (cpu_record, &tmp,
(void * (*) (void *))cpu_record_hash_alloc);
pthread_mutex_lock (&cpu_record_mtx);
{
thread->hist = hash_get (cpu_record, &tmp,
(void * (*) (void *))cpu_record_hash_alloc);
}
pthread_mutex_unlock (&cpu_record_mtx);
}
thread->hist->total_active++;
thread->func = func;
@ -650,15 +698,45 @@ static int
fd_select (struct thread_master *m, int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *timer_wait)
{
int num;
/* If timer_wait is null here, that means either select() or poll() should
* block indefinitely, unless the thread_master has overriden it. select()
* and poll() differ in the timeout values they interpret as an indefinite
* block; select() requires a null pointer, while poll takes a millisecond
* value of -1.
*
* The thread_master owner has the option of overriding the default behavior
* by setting ->selectpoll_timeout. If the value is positive, it specifies
* the maximum number of milliseconds to wait. If the timeout is -1, it
* specifies that we should never wait and always return immediately even if
* no event is detected. If the value is zero, the behavior is default.
*/
#if defined(HAVE_POLL)
/* recalc timeout for poll. Attention NULL pointer is no timeout with
select, where with poll no timeount is -1 */
int timeout = -1;
if (timer_wait != NULL)
if (timer_wait != NULL && m->selectpoll_timeout == 0) // use the default value
timeout = (timer_wait->tv_sec*1000) + (timer_wait->tv_usec/1000);
else if (m->selectpoll_timeout > 0) // use the user's timeout
timeout = m->selectpoll_timeout;
else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
timeout = 0;
num = poll (m->handler.pfds, m->handler.pfdcount + m->handler.pfdcountsnmp, timeout);
#else
struct timeval timeout;
if (m->selectpoll_timeout > 0) // use the user's timeout
{
timeout.tv_sec = m->selectpoll_timeout / 1000;
timeout.tv_usec = (m->selectpoll_timeout % 1000) * 1000;
timer_wait = &timeout;
}
else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
{
timeout.tv_sec = 0;
timeout.tv_usec = 0;
timer_wait = &timeout;
}
num = select (size, read, write, except, timer_wait);
#endif
@ -703,36 +781,43 @@ funcname_thread_add_read_write (int dir, struct thread_master *m,
{
struct thread *thread = NULL;
#if !defined(HAVE_POLL)
thread_fd_set *fdset = NULL;
if (dir == THREAD_READ)
fdset = &m->handler.readfd;
else
fdset = &m->handler.writefd;
#endif
pthread_mutex_lock (&m->mtx);
{
#if defined (HAVE_POLL)
thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
if (thread == NULL)
return NULL;
thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
#else
if (FD_ISSET (fd, fdset))
{
zlog_warn ("There is already %s fd [%d]",
(dir == THREAD_READ) ? "read" : "write", fd);
return NULL;
}
thread_fd_set *fdset = NULL;
if (dir == THREAD_READ)
fdset = &m->handler.readfd;
else
fdset = &m->handler.writefd;
FD_SET (fd, fdset);
thread = thread_get (m, dir, func, arg, debugargpass);
if (FD_ISSET (fd, fdset))
{
zlog_warn ("There is already %s fd [%d]",
(dir == THREAD_READ) ? "read" : "write", fd);
}
else
{
FD_SET (fd, fdset);
thread = thread_get (m, dir, func, arg, debugargpass);
}
#endif
thread->u.fd = fd;
if (dir == THREAD_READ)
thread_add_fd (m->read, thread);
else
thread_add_fd (m->write, thread);
if (thread)
{
pthread_mutex_lock (&thread->mtx);
{
thread->u.fd = fd;
if (dir == THREAD_READ)
thread_add_fd (m->read, thread);
else
thread_add_fd (m->write, thread);
}
pthread_mutex_unlock (&thread->mtx);
}
}
pthread_mutex_unlock (&m->mtx);
return thread;
}
@ -753,13 +838,21 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
assert (time_relative);
queue = ((type == THREAD_TIMER) ? m->timer : m->background);
thread = thread_get (m, type, func, arg, debugargpass);
pthread_mutex_lock (&m->mtx);
{
queue = ((type == THREAD_TIMER) ? m->timer : m->background);
thread = thread_get (m, type, func, arg, debugargpass);
monotime(&thread->u.sands);
timeradd(&thread->u.sands, time_relative, &thread->u.sands);
pthread_mutex_lock (&thread->mtx);
{
monotime(&thread->u.sands);
timeradd(&thread->u.sands, time_relative, &thread->u.sands);
pqueue_enqueue(thread, queue);
}
pthread_mutex_unlock (&thread->mtx);
}
pthread_mutex_unlock (&m->mtx);
pqueue_enqueue(thread, queue);
return thread;
}
@ -847,9 +940,17 @@ funcname_thread_add_event (struct thread_master *m,
assert (m != NULL);
thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
thread->u.val = val;
thread_list_add (&m->event, thread);
pthread_mutex_lock (&m->mtx);
{
thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
pthread_mutex_lock (&thread->mtx);
{
thread->u.val = val;
thread_list_add (&m->event, thread);
}
pthread_mutex_unlock (&thread->mtx);
}
pthread_mutex_unlock (&m->mtx);
return thread;
}
@ -880,14 +981,22 @@ thread_cancel_read_or_write (struct thread *thread, short int state)
fd_clear_read_write (thread);
}
/* Cancel thread from scheduler. */
/**
* Cancel thread from scheduler.
*
* This function is *NOT* MT-safe. DO NOT call it from any other pthread except
* the one which owns thread->master.
*/
void
thread_cancel (struct thread *thread)
{
struct thread_list *list = NULL;
struct pqueue *queue = NULL;
struct thread **thread_array = NULL;
pthread_mutex_lock (&thread->master->mtx);
pthread_mutex_lock (&thread->mtx);
switch (thread->type)
{
case THREAD_READ:
@ -919,15 +1028,14 @@ thread_cancel (struct thread *thread)
queue = thread->master->background;
break;
default:
return;
goto done;
break;
}
if (queue)
{
assert(thread->index >= 0);
assert(thread == queue->array[thread->index]);
pqueue_remove_at(thread->index, queue);
pqueue_remove (thread, queue);
}
else if (list)
{
@ -943,6 +1051,10 @@ thread_cancel (struct thread *thread)
}
thread_add_unuse (thread->master, thread);
done:
pthread_mutex_unlock (&thread->mtx);
pthread_mutex_unlock (&thread->master->mtx);
}
/* Delete all events which has argument value arg. */
@ -951,39 +1063,48 @@ thread_cancel_event (struct thread_master *m, void *arg)
{
unsigned int ret = 0;
struct thread *thread;
struct thread *t;
thread = m->event.head;
while (thread)
{
struct thread *t;
t = thread;
thread = t->next;
if (t->arg == arg)
pthread_mutex_lock (&m->mtx);
{
thread = m->event.head;
while (thread)
{
t = thread;
pthread_mutex_lock (&t->mtx);
{
ret++;
thread_list_delete (&m->event, t);
thread_add_unuse (m, t);
thread = t->next;
if (t->arg == arg)
{
ret++;
thread_list_delete (&m->event, t);
thread_add_unuse (m, t);
}
}
}
pthread_mutex_unlock (&t->mtx);
}
/* thread can be on the ready list too */
thread = m->ready.head;
while (thread)
{
struct thread *t;
t = thread;
thread = t->next;
if (t->arg == arg)
/* thread can be on the ready list too */
thread = m->ready.head;
while (thread)
{
t = thread;
pthread_mutex_lock (&t->mtx);
{
ret++;
thread_list_delete (&m->ready, t);
thread_add_unuse (m, t);
thread = t->next;
if (t->arg == arg)
{
ret++;
thread_list_delete (&m->ready, t);
thread_add_unuse (m, t);
}
}
}
pthread_mutex_unlock (&t->mtx);
}
}
pthread_mutex_unlock (&m->mtx);
return ret;
}
@ -1143,18 +1264,24 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
struct timeval *timer_wait = &timer_val;
struct timeval *timer_wait_bg;
while (1)
do
{
int num = 0;
/* Signals pre-empt everything */
quagga_sigevent_process ();
if (m->handle_signals)
quagga_sigevent_process ();
pthread_mutex_lock (&m->mtx);
/* Drain the ready queue of already scheduled jobs, before scheduling
* more.
*/
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
{
fetch = thread_run (m, thread, fetch);
pthread_mutex_unlock (&m->mtx);
return fetch;
}
/* To be fair to all kinds of threads, and avoid starvation, we
* need to be careful to consider all thread types for scheduling
@ -1194,8 +1321,12 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
if (num < 0)
{
if (errno == EINTR)
continue; /* signal received - process it */
{
pthread_mutex_unlock (&m->mtx);
continue; /* signal received - process it */
}
zlog_warn ("select() error: %s", safe_strerror (errno));
pthread_mutex_unlock (&m->mtx);
return NULL;
}
@ -1215,15 +1346,28 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
list at this time. If this is code is uncommented, then background
timer threads will not run unless there is nothing else to do. */
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
{
fetch = thread_run (m, thread, fetch);
pthread_mutex_unlock (&m->mtx);
return fetch;
}
#endif
/* Background timer/events, lowest priority */
thread_timer_process (m->background, &now);
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
}
{
fetch = thread_run (m, thread, fetch);
pthread_mutex_unlock (&m->mtx);
return fetch;
}
pthread_mutex_unlock (&m->mtx);
} while (m->spin);
return NULL;
}
unsigned long
@ -1248,13 +1392,23 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
int
thread_should_yield (struct thread *thread)
{
return monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
int result;
pthread_mutex_lock (&thread->mtx);
{
result = monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
}
pthread_mutex_unlock (&thread->mtx);
return result;
}
void
thread_set_yield_time (struct thread *thread, unsigned long yield_time)
{
thread->yield = yield_time;
pthread_mutex_lock (&thread->mtx);
{
thread->yield = yield_time;
}
pthread_mutex_unlock (&thread->mtx);
}
void
@ -1324,6 +1478,7 @@ funcname_thread_execute (struct thread_master *m,
memset (&dummy, 0, sizeof (struct thread));
pthread_mutex_init (&dummy.mtx, NULL);
dummy.type = THREAD_EVENT;
dummy.add_type = THREAD_EXECUTE;
dummy.master = NULL;
@ -1332,8 +1487,12 @@ funcname_thread_execute (struct thread_master *m,
tmp.func = dummy.func = func;
tmp.funcname = dummy.funcname = funcname;
dummy.hist = hash_get (cpu_record, &tmp,
(void * (*) (void *))cpu_record_hash_alloc);
pthread_mutex_lock (&cpu_record_mtx);
{
dummy.hist = hash_get (cpu_record, &tmp,
(void * (*) (void *))cpu_record_hash_alloc);
}
pthread_mutex_unlock (&cpu_record_mtx);
dummy.schedfrom = schedfrom;
dummy.schedfrom_line = fromln;

View File

@ -24,6 +24,7 @@
#include <zebra.h>
#include "monotime.h"
#include <pthread.h>
struct rusage_t
{
@ -84,6 +85,10 @@ struct thread_master
int fd_limit;
struct fd_handler handler;
unsigned long alloc;
long selectpoll_timeout;
bool spin;
bool handle_signals;
pthread_mutex_t mtx;
};
typedef unsigned char thread_type;
@ -110,6 +115,7 @@ struct thread
const char *funcname;
const char *schedfrom;
int schedfrom_line;
pthread_mutex_t mtx;
};
struct cpu_thread_history

View File

@ -746,9 +746,11 @@ vty_end_config (struct vty *vty)
case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
case BGP_IPV6L_NODE:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:

View File

@ -733,6 +733,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
s = zclient->obuf;
stream_reset (s);
/* Some checks for labeled-unicast. The current expectation is that each
* nexthop is accompanied by a label in the case of labeled-unicast.
*/
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
/* We expect prefixes installed with labels and the number to match
* the number of nexthops.
*/
assert (api->label_num == api->nexthop_num);
}
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
@ -749,7 +761,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
{
/* traditional 32-bit data units */
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
{
@ -765,6 +777,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
{
stream_putc (s, NEXTHOP_TYPE_IPV4);
stream_put_in_addr (s, api->nexthop[i]);
/* For labeled-unicast, each nexthop is followed by label. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
stream_putl (s, api->label[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
@ -800,6 +815,18 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
s = zclient->obuf;
stream_reset (s);
/* Some checks for labeled-unicast. The current expectation is that each
* nexthop is accompanied by a label in the case of labeled-unicast.
*/
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
/* We expect prefixes installed with labels and the number to match
* the number of nexthops.
*/
assert (api->label_num == api->nexthop_num);
}
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
@ -831,6 +858,9 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
{
stream_putc (s, NEXTHOP_TYPE_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
/* For labeled-unicast, each nexthop is followed by label. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
stream_putl (s, api->label[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
@ -869,6 +899,18 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
s = zclient->obuf;
stream_reset (s);
/* Some checks for labeled-unicast. The current expectation is that each
* nexthop is accompanied by a label in the case of labeled-unicast.
*/
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
/* We expect prefixes installed with labels and the number to match
* the number of nexthops.
*/
assert (api->label_num == api->nexthop_num);
}
zclient_create_header (s, cmd, api->vrf_id);
/* Put type and nexthop. */
@ -907,6 +949,9 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
{
stream_putc (s, NEXTHOP_TYPE_IPV6);
stream_write (s, (u_char *)api->nexthop[i], 16);
/* For labeled-unicast, each nexthop is followed by label. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
stream_putl (s, api->label[i]);
}
for (i = 0; i < api->ifindex_num; i++)
{
@ -1879,6 +1924,12 @@ zclient_read (struct thread *thread)
if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length);
break;
case ZEBRA_FEC_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd fec update\n");
if (zclient->fec_update)
(*zclient->fec_update) (command, zclient, length);
break;
default:
break;
}

View File

@ -94,6 +94,9 @@ typedef enum {
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_GET_LABEL_CHUNK,
ZEBRA_RELEASE_LABEL_CHUNK,
ZEBRA_FEC_REGISTER,
ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE,
} zebra_message_types_t;
struct redist_proto
@ -164,6 +167,7 @@ struct zclient
int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*fec_update) (int, struct zclient *, uint16_t);
};
/* Zebra API message flag. */
@ -174,6 +178,7 @@ struct zclient
#define ZAPI_MESSAGE_TAG 0x10
#define ZAPI_MESSAGE_MTU 0x20
#define ZAPI_MESSAGE_SRCPFX 0x40
#define ZAPI_MESSAGE_LABEL 0x80
/* Zserv protocol message header */
struct zserv_header
@ -206,6 +211,9 @@ struct zapi_ipv4
u_char ifindex_num;
ifindex_t *ifindex;
u_char label_num;
unsigned int *label;
u_char distance;
u_int32_t metric;
@ -297,6 +305,9 @@ struct zapi_ipv6
u_char ifindex_num;
ifindex_t *ifindex;
u_char label_num;
unsigned int *label;
u_char distance;
u_int32_t metric;

View File

@ -393,6 +393,9 @@ extern const char *zserv_command_string (unsigned int command);
#define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
/* Zebra FEC flags. */
#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
#endif
@ -413,11 +416,13 @@ typedef enum {
#define SAFI_ENCAP 5
#define SAFI_RESERVED_5 5
#define SAFI_EVPN 6
#define SAFI_MAX 7
#define SAFI_LABELED_UNICAST 7
#define SAFI_MAX 8
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1
#define IANA_SAFI_MULTICAST 2
#define IANA_SAFI_LABELED_UNICAST 4
#define IANA_SAFI_ENCAP 7
#define IANA_SAFI_MPLS_VPN 128
@ -512,6 +517,8 @@ static inline safi_t safi_iana2int (safi_t safi)
return SAFI_ENCAP;
if (safi == IANA_SAFI_EVPN)
return SAFI_EVPN;
if (safi == IANA_SAFI_LABELED_UNICAST)
return SAFI_LABELED_UNICAST;
return SAFI_MAX;
}
@ -527,6 +534,8 @@ static inline safi_t safi_int2iana (safi_t safi)
return IANA_SAFI_ENCAP;
if (safi == SAFI_EVPN)
return IANA_SAFI_EVPN;
if (safi == SAFI_LABELED_UNICAST)
return IANA_SAFI_LABELED_UNICAST;
return IANA_SAFI_RESERVED;
}

View File

@ -0,0 +1,8 @@
# Additional protocol strings defined by frr for each of its daemons
186 bgp
187 isis
188 ospf
189 rip
190 ripng
191 static

View File

@ -532,8 +532,15 @@ case "$1" in
fi
if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
echo "Removing all routes made by zebra."
echo "Removing all routes made by FRR."
ip route flush proto bgp
ip route flush proto ospf
ip route flush proto static
ip route flush proto rip
ip route flush proto ripng
ip route flush proto zebra
ip route flush proto isis
else
[ -n "$dmn" ] && eval "${dmn/-/_}=0"
start_watchfrr

View File

@ -310,7 +310,8 @@ vtysh_execute_func (const char *line, int pager)
|| saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE
|| saved_node == BGP_IPV4_NODE
|| saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
|| saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
|| saved_node == BGP_IPV4L_NODE || saved_node == BGP_IPV6L_NODE
|| saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
&& (tried == 1))
{
vtysh_execute("exit-address-family");
@ -948,6 +949,12 @@ static struct cmd_node bgp_ipv4m_node =
"%s(config-router-af)# "
};
static struct cmd_node bgp_ipv4l_node =
{
BGP_IPV4L_NODE,
"%s(config-router-af)# "
};
static struct cmd_node bgp_ipv6_node =
{
BGP_IPV6_NODE,
@ -966,6 +973,12 @@ static struct cmd_node bgp_evpn_node =
"%s(config-router-af)# "
};
static struct cmd_node bgp_ipv6l_node =
{
BGP_IPV6L_NODE,
"%s(config-router-af)# "
};
static struct cmd_node bgp_vnc_defaults_node =
{
BGP_VNC_DEFAULTS_NODE,
@ -1122,7 +1135,7 @@ DEFUNSH (VTYSH_BGPD,
"address-family vpnv4 [unicast]",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family Modifier\n")
"Address Family modifier\n")
{
vty->node = BGP_VPNV4_NODE;
return CMD_SUCCESS;
@ -1134,7 +1147,7 @@ DEFUNSH (VTYSH_BGPD,
"address-family vpnv6 [unicast]",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family Modifier\n")
"Address Family modifier\n")
{
vty->node = BGP_VPNV6_NODE;
return CMD_SUCCESS;
@ -1164,15 +1177,16 @@ DEFUNSH (VTYSH_BGPD,
}
DEFUNSH (VTYSH_BGPD,
address_family_ipv4_unicast,
address_family_ipv4_unicast_cmd,
"address-family ipv4 [<unicast|multicast|vpn|encap>]",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
"Address Family Modifier\n")
address_family_ipv4,
address_family_ipv4_cmd,
"address-family ipv4 [<unicast|multicast|vpn|encap|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n")
{
int idx = 0;
@ -1185,6 +1199,9 @@ DEFUNSH (VTYSH_BGPD,
else if (argv_find (argv, argc, "vpn", &idx))
vty->node = BGP_VPNV4_NODE;
else if (argv_find (argv, argc, "labeled-unicast", &idx))
vty->node = BGP_IPV4L_NODE;
else
vty->node = BGP_IPV4_NODE;
@ -1192,15 +1209,16 @@ DEFUNSH (VTYSH_BGPD,
}
DEFUNSH (VTYSH_BGPD,
address_family_ipv6,
address_family_ipv6_cmd,
"address-family ipv6 [<unicast|multicast|vpn|encap>]",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
"Address Family Modifier\n")
address_family_ipv6,
address_family_ipv6_cmd,
"address-family ipv6 [<unicast|multicast|vpn|encap|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n")
{
int idx = 0;
@ -1213,6 +1231,9 @@ DEFUNSH (VTYSH_BGPD,
else if (argv_find (argv, argc, "vpn", &idx))
vty->node = BGP_VPNV6_NODE;
else if (argv_find (argv, argc, "labeled-unicast", &idx))
vty->node = BGP_IPV6L_NODE;
else
vty->node = BGP_IPV6_NODE;
@ -1550,8 +1571,10 @@ vtysh_exit (struct vty *vty)
case BGP_ENCAPV6_NODE:
case BGP_IPV4_NODE:
case BGP_IPV4M_NODE:
case BGP_IPV4L_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_IPV6L_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_EVPN_NODE:
case BGP_VNC_DEFAULTS_NODE:
@ -1610,11 +1633,13 @@ DEFUNSH (VTYSH_BGPD,
{
if (vty->node == BGP_IPV4_NODE
|| vty->node == BGP_IPV4M_NODE
|| vty->node == BGP_IPV4L_NODE
|| vty->node == BGP_VPNV4_NODE
|| vty->node == BGP_VPNV6_NODE
|| vty->node == BGP_ENCAP_NODE
|| vty->node == BGP_ENCAPV6_NODE
|| vty->node == BGP_IPV6_NODE
|| vty->node == BGP_IPV6L_NODE
|| vty->node == BGP_IPV6M_NODE)
vty->node = BGP_NODE;
return CMD_SUCCESS;
@ -3160,8 +3185,10 @@ vtysh_init_vty (void)
install_node (&bgp_encapv6_node, NULL);
install_node (&bgp_ipv4_node, NULL);
install_node (&bgp_ipv4m_node, NULL);
install_node (&bgp_ipv4l_node, NULL);
install_node (&bgp_ipv6_node, NULL);
install_node (&bgp_ipv6m_node, NULL);
install_node (&bgp_ipv6l_node, NULL);
install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_evpn_node, NULL);
install_node (&bgp_vnc_defaults_node, NULL);
@ -3199,9 +3226,11 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_ENCAPV6_NODE);
vtysh_install_default (BGP_IPV4_NODE);
vtysh_install_default (BGP_IPV4M_NODE);
vtysh_install_default (BGP_IPV4L_NODE);
vtysh_install_default (BGP_IPV6_NODE);
vtysh_install_default (BGP_IPV6M_NODE);
vtysh_install_default (BGP_EVPN_NODE);
vtysh_install_default (BGP_IPV6L_NODE);
#if ENABLE_BGP_VNC
vtysh_install_default (BGP_VRF_POLICY_NODE);
vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
@ -3273,11 +3302,15 @@ vtysh_init_vty (void)
install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
#if defined (ENABLE_BGP_VNC)
install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
@ -3317,12 +3350,14 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV4L_NODE, &vtysh_end_all_cmd);
install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd);
install_element (BGP_VPNV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_ENCAP_NODE, &vtysh_end_all_cmd);
install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6L_NODE, &vtysh_end_all_cmd);
install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
@ -3379,7 +3414,7 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &vnc_nve_group_cmd);
install_element (BGP_NODE, &vnc_l2_group_cmd);
#endif
install_element (BGP_NODE, &address_family_ipv4_unicast_cmd);
install_element (BGP_NODE, &address_family_ipv4_cmd);
install_element (BGP_NODE, &address_family_ipv6_cmd);
install_element (BGP_NODE, &address_family_evpn_cmd);
install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
@ -3388,9 +3423,11 @@ vtysh_init_vty (void)
install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4L_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6L_NODE, &exit_address_family_cmd);
install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);

View File

@ -31,7 +31,7 @@ zebra_SOURCES = \
redistribute.c debug.c rtadv.c zebra_vty.c \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c \
zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls_vty.c \
zebra_mroute.c \
label_manager.c \
# end
@ -40,7 +40,7 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c
zebra_memory.c zebra_mpls_vty.c zebra_mpls_null.c
noinst_HEADERS = \
zebra_memory.h \
@ -88,7 +88,7 @@ EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \
rt_socket.c rtread_netlink.c rtread_sysctl.c \
rtread_getmsg.c kernel_socket.c kernel_netlink.c \
ioctl.c ioctl_solaris.c \
zebra_mpls_netlink.c zebra_mpls_openbsd.c \
zebra_mpls_netlink.c zebra_mpls_openbsd.c zebra_mpls.c \
GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB
client : client_main.o ../lib/libfrr.la

View File

@ -691,6 +691,7 @@ if_delete_update (struct interface *ifp)
for setting ifindex to IFINDEX_INTERNAL after processing the
interface deletion message. */
ifp->ifindex = IFINDEX_INTERNAL;
ifp->node = NULL;
}
/* VRF change for an interface */

View File

@ -100,6 +100,11 @@ static const struct message rtproto_str[] = {
{RTPROT_BIRD, "BIRD"},
#endif /* RTPROT_BIRD */
{RTPROT_MROUTED, "mroute"},
{RTPROT_BGP, "BGP"},
{RTPROT_OSPF, "OSPF"},
{RTPROT_ISIS, "IS-IS"},
{RTPROT_RIP, "RIP"},
{RTPROT_RIPNG, "RIPNG"},
{0, NULL}
};

View File

@ -372,7 +372,7 @@ extern void rib_init (void);
extern unsigned long rib_score_proto (u_char proto, u_short instance);
extern void rib_queue_add (struct route_node *rn);
extern void meta_queue_free (struct meta_queue *mq);
extern int zebra_rib_labeled_unicast (struct rib *rib);
extern struct route_table *rib_table_ipv6;
extern void rib_unlink (struct route_node *, struct rib *);

View File

@ -103,6 +103,47 @@ struct gw_family_t
union g_addr gate;
};
static inline int is_selfroute(int proto)
{
if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) ||
(proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA) ||
(proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)) {
return 1;
}
return 0;
}
static inline int get_rt_proto(int proto)
{
switch (proto) {
case ZEBRA_ROUTE_BGP:
proto = RTPROT_BGP;
break;
case ZEBRA_ROUTE_OSPF:
case ZEBRA_ROUTE_OSPF6:
proto = RTPROT_OSPF;
break;
case ZEBRA_ROUTE_STATIC:
proto = RTPROT_STATIC;
break;
case ZEBRA_ROUTE_ISIS:
proto = RTPROT_ISIS;
break;
case ZEBRA_ROUTE_RIP:
proto = RTPROT_RIP;
break;
case ZEBRA_ROUTE_RIPNG:
proto = RTPROT_RIPNG;
break;
default:
proto = RTPROT_ZEBRA;
break;
}
return proto;
}
/*
Pending: create an efficient table_id (in a tree/hash) based lookup)
*/
@ -171,7 +212,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
return 0;
if (!startup &&
rtm->rtm_protocol == RTPROT_ZEBRA &&
is_selfroute (rtm->rtm_protocol) &&
h->nlmsg_type == RTM_NEWROUTE)
return 0;
@ -196,7 +237,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
}
/* Route which inserted by Zebra. */
if (rtm->rtm_protocol == RTPROT_ZEBRA)
if (is_selfroute(rtm->rtm_protocol))
flags |= ZEBRA_FLAG_SELFROUTE;
if (tb[RTA_OIF])
@ -1137,7 +1178,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
req.r.rtm_family = family;
req.r.rtm_dst_len = p->prefixlen;
req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
req.r.rtm_protocol = RTPROT_ZEBRA;
req.r.rtm_protocol = get_rt_proto(rib->type);
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))

View File

@ -28,6 +28,14 @@
#define NL_DEFAULT_ROUTE_METRIC 20
/* Additional protocol strings to push into routes */
#define RTPROT_BGP 186
#define RTPROT_ISIS 187
#define RTPROT_OSPF 188
#define RTPROT_RIP 189
#define RTPROT_RIPNG 190
extern void
clear_nhlfe_installed (zebra_lsp_t *lsp);
extern int

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,7 @@ typedef struct zebra_snhlfe_t_ zebra_snhlfe_t;
typedef struct zebra_slsp_t_ zebra_slsp_t;
typedef struct zebra_nhlfe_t_ zebra_nhlfe_t;
typedef struct zebra_lsp_t_ zebra_lsp_t;
typedef struct zebra_fec_t_ zebra_fec_t;
/*
* (Outgoing) nexthop label forwarding entry configuration
@ -147,6 +148,27 @@ struct zebra_lsp_t_
u_char addr_family;
};
/*
* FEC to label binding.
*/
struct zebra_fec_t_
{
/* FEC (prefix) */
struct route_node *rn;
/* In-label - either statically bound or derived from label block. */
mpls_label_t label;
/* Label index (into global label block), if valid */
u_int32_t label_index;
/* Flags. */
u_int32_t flags;
#define FEC_FLAG_CONFIGURED (1 << 0)
/* Clients interested in this FEC. */
struct list *client_list;
};
/* Function declarations. */
@ -164,6 +186,116 @@ char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
char *buf, int len);
/*
* Add/update global label block.
*/
int
zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label,
u_int32_t end_label);
/*
* Delete global label block.
*/
int
zebra_mpls_label_block_del (struct zebra_vrf *vrf);
/*
* Display MPLS global label block configuration (VTY command handler).
*/
int
zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *vrf);
/*
* Install dynamic LSP entry.
*/
int
zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
/*
* Uninstall dynamic LSP entry, if any.
*/
int
zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
/*
* Registration from a client for the label binding for a FEC. If a binding
* already exists, it is informed to the client.
* NOTE: If there is a manually configured label binding, that is used.
* Otherwise, if aa label index is specified, it means we have to allocate the
* label from a locally configured label block (SRGB), if one exists and index
* is acceptable.
*/
int
zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
u_int32_t label_index, struct zserv *client);
/*
* Deregistration from a client for the label binding for a FEC. The FEC
* itself is deleted if no other registered clients exist and there is no
* label bound to the FEC.
*/
int
zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
struct zserv *client);
/*
* Cleanup any FECs registered by this client.
*/
int
zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client);
/*
* Return FEC (if any) to which this label is bound.
* Note: Only works for per-prefix binding and when the label is not
* implicit-null.
* TODO: Currently walks entire table, can optimize later with another
* hash..
*/
zebra_fec_t *
zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label);
/*
* Inform if specified label is currently bound to a FEC or not.
*/
int
zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
/*
* Add static FEC to label binding. If there are clients registered for this
* FEC, notify them. If there are labeled routes for this FEC, install the
* label forwarding entry.
*/
int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
mpls_label_t in_label);
/*
* Remove static FEC to label binding. If there are no clients registered
* for this FEC, delete the FEC; else notify clients.
* Note: Upon delete of static binding, if label index exists for this FEC,
* client may need to be updated with derived label.
*/
int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
/*
* Display MPLS FEC to label binding configuration (VTY command handler).
*/
int
zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf);
/*
* Display MPLS FEC to label binding (VTY command handler).
*/
void
zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf);
/*
* Display MPLS FEC to label binding for a specific FEC (VTY command handler).
*/
void
zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p);
/*
* Install/uninstall a FEC-To-NHLFE (FTN) binding.
*/
@ -182,7 +314,7 @@ 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);
ifindex_t ifindex);
/*
* Uninstall a particular NHLFE in the forwarding table. If this is
@ -191,7 +323,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
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);
union g_addr *gate, ifindex_t ifindex);
/*
* Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
@ -216,7 +348,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi);
int
zebra_mpls_lsp_label_consistent (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);
union g_addr *gate, ifindex_t ifindex);
#endif /* HAVE_CUMULUS */
/*
@ -229,7 +361,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
int
zebra_mpls_static_lsp_add (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);
union g_addr *gate, ifindex_t ifindex);
/*
* Delete static LSP entry. This may be the delete of one particular
@ -241,7 +373,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
int
zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
enum nexthop_types_t gtype, union g_addr *gate,
char *ifname, ifindex_t ifindex);
ifindex_t ifindex);
/*
* Schedule all MPLS label forwarding entries for processing.
@ -324,6 +456,8 @@ lsp_type_from_rib_type (int rib_type)
{
case ZEBRA_ROUTE_STATIC:
return ZEBRA_LSP_STATIC;
case ZEBRA_ROUTE_BGP:
return ZEBRA_LSP_BGP;
default:
return ZEBRA_LSP_NONE;
}
@ -339,6 +473,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type)
return "Static";
case ZEBRA_LSP_LDP:
return "LDP";
case ZEBRA_LSP_BGP:
return "BGP";
default:
return "Unknown";
}

View File

@ -27,3 +27,209 @@ int kernel_add_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
int mpls_kernel_init (void) { return -1; };
int mpls_enabled;
char *
mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
char *buf, int len)
{
return NULL;
}
int
mpls_str2label (const char *label_str, u_int8_t *num_labels,
mpls_label_t *labels)
{
return 0;
}
int
zebra_mpls_label_block_add (struct zebra_vrf *vrf, u_int32_t start_label,
u_int32_t end_label)
{
return 0;
}
int
zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
{
return 0;
}
int
zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf)
{
return 0;
}
int
zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
{
return 0;
}
int
zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
{
return 0;
}
void
zebra_mpls_init_tables (struct zebra_vrf *zvrf)
{
}
void
zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
u_char use_json)
{
}
void
zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
u_char use_json)
{
}
int
zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
{
return 0;
}
#ifdef HAVE_CUMULUS
int
zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
mpls_label_t out_label, enum nexthop_types_t gtype,
union g_addr *gate, ifindex_t ifindex)
{
return 0;
}
#endif
int
zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
mpls_label_t out_label, enum nexthop_types_t gtype,
union g_addr *gate, ifindex_t ifindex)
{
return 0;
}
int
zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
enum nexthop_types_t gtype, union g_addr *gate,
ifindex_t ifindex)
{
return 0;
}
void
zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
{
}
void
zebra_mpls_close_tables (struct zebra_vrf *zvrf)
{
}
zebra_fec_t *
zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
{
return NULL;
}
int
zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
{
return 0;
}
int
zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
mpls_label_t in_label)
{
return 0;
}
int
zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
{
return 0;
}
int
zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
{
return 0;
}
void
zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
{
}
void
zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
{
}
int
zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
u_int32_t label_index, struct zserv *client)
{
return 0;
}
int
zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
struct zserv *client)
{
return 0;
}
int
zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
{
return 0;
}
void mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt)
{
return;
}
void mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
{
return;
}
void zebra_mpls_init (void)
{
return;
}
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,
ifindex_t ifindex)
{
return 0;
}
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, ifindex_t ifindex)
{
return 0;
}
int mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
struct prefix *prefix, enum nexthop_types_t gtype,
union g_addr *gate, ifindex_t ifindex, u_int8_t distance,
mpls_label_t out_label)
{
return 0;
}

View File

@ -133,7 +133,7 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
#if defined(HAVE_CUMULUS)
/* Check that label value is consistent. */
if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype,
&gate, NULL, 0))
&gate, 0))
{
vty_out (vty, "%% Label value not consistent%s",
VTY_NEWLINE);
@ -142,10 +142,10 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
#endif /* HAVE_CUMULUS */
ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype,
&gate, NULL, 0);
&gate, 0);
}
else
ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0);
ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, 0);
if (ret)
{
@ -209,6 +209,109 @@ DEFUN (no_mpls_transit_lsp_all,
return zebra_mpls_transit_lsp (vty, 0, argv[3]->arg, NULL, NULL, NULL);
}
static int
zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix,
const char *label_str)
{
struct zebra_vrf *zvrf;
struct prefix p;
u_int32_t label;
int ret;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
{
vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
return CMD_WARNING;
}
memset(&p, 0, sizeof(struct prefix));
ret = str2prefix(prefix, &p);
if (ret <= 0)
{
vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (add_cmd)
{
if (!label_str)
{
vty_out (vty, "%% No label binding specified%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (!strcmp(label_str, "implicit-null"))
label = MPLS_IMP_NULL_LABEL;
else if (!strcmp(label_str, "explicit-null"))
{
if (p.family == AF_INET)
label = MPLS_V4_EXP_NULL_LABEL;
else
label = MPLS_V6_EXP_NULL_LABEL;
}
else
{
label = atoi(label_str);
if (!IS_MPLS_UNRESERVED_LABEL(label))
{
vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (zebra_mpls_label_already_bound (zvrf, label))
{
vty_out (vty, "%% Label already bound to a FEC%s",
VTY_NEWLINE);
return CMD_WARNING;
}
}
ret = zebra_mpls_static_fec_add (zvrf, &p, label);
}
else
ret = zebra_mpls_static_fec_del (zvrf, &p);
if (ret)
{
vty_out (vty, "%% FEC to label binding cannot be %s%s",
add_cmd ? "added" : "deleted", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN (mpls_label_bind,
mpls_label_bind_cmd,
"mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null|explicit-null>",
MPLS_STR
"Label configuration\n"
"Establish FEC to label binding\n"
"IPv4 prefix\n"
"IPv6 prefix\n"
"MPLS Label to bind\n"
"Use Implicit-Null Label\n"
"Use Explicit-Null Label\n")
{
return zebra_mpls_bind (vty, 1, argv[3]->arg, argv[4]->arg);
}
DEFUN (no_mpls_label_bind,
no_mpls_label_bind_cmd,
"no mpls label bind <A.B.C.D/M|X:X::X:X/M> [<(16-1048575)|implicit-null>]",
NO_STR
MPLS_STR
"Label configuration\n"
"Establish FEC to label binding\n"
"IPv4 prefix\n"
"IPv6 prefix\n"
"MPLS Label to bind\n"
"Use Implicit-Null Label\n")
{
return zebra_mpls_bind (vty, 0, argv[4]->arg, NULL);
}
/* Static route configuration. */
DEFUN (ip_route_label,
ip_route_label_cmd,
@ -777,9 +880,45 @@ zebra_mpls_config (struct vty *vty)
return 0;
write += zebra_mpls_write_lsp_config(vty, zvrf);
write += zebra_mpls_write_fec_config(vty, zvrf);
write += zebra_mpls_write_label_block_config (vty, zvrf);
return write;
}
DEFUN (show_mpls_fec,
show_mpls_fec_cmd,
"show mpls fec [<A.B.C.D/M|X:X::X:X/M>]",
SHOW_STR
MPLS_STR
"MPLS FEC table\n"
"FEC to display information about\n"
"FEC to display information about\n")
{
struct zebra_vrf *zvrf;
struct prefix p;
int ret;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return 0;
if (argc == 3)
zebra_mpls_print_fec_table(vty, zvrf);
else
{
memset(&p, 0, sizeof(struct prefix));
ret = str2prefix(argv[3]->arg, &p);
if (ret <= 0)
{
vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
return CMD_WARNING;
}
zebra_mpls_print_fec (vty, zvrf, &p);
}
return CMD_SUCCESS;
}
DEFUN (show_mpls_table,
show_mpls_table_cmd,
"show mpls table [json]",
@ -827,6 +966,85 @@ DEFUN (show_mpls_status,
return CMD_SUCCESS;
}
static int
zebra_mpls_global_block (struct vty *vty, int add_cmd,
const char *start_label_str, const char *end_label_str)
{
int ret;
u_int32_t start_label;
u_int32_t end_label;
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
if (!zvrf)
{
vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (add_cmd)
{
if (!start_label_str || !end_label_str)
{
vty_out (vty, "%% Labels not specified%s", VTY_NEWLINE);
return CMD_WARNING;
}
start_label = atoi(start_label_str);
end_label = atoi(end_label_str);
if (!IS_MPLS_UNRESERVED_LABEL(start_label) ||
!IS_MPLS_UNRESERVED_LABEL(end_label))
{
vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (end_label < start_label)
{
vty_out (vty, "%% End label is less than Start label%s",
VTY_NEWLINE);
return CMD_WARNING;
}
ret = zebra_mpls_label_block_add (zvrf, start_label, end_label);
}
else
ret = zebra_mpls_label_block_del (zvrf);
if (ret)
{
vty_out (vty, "%% Global label block could not be %s%s",
add_cmd ? "added" : "deleted", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN (mpls_label_global_block,
mpls_label_global_block_cmd,
"mpls label global-block (16-1048575) (16-1048575)",
MPLS_STR
"Label configuration\n"
"Configure global label block\n"
"Start label\n"
"End label\n")
{
return zebra_mpls_global_block (vty, 1, argv[3]->arg, argv[4]->arg);
}
DEFUN (no_mpls_label_global_block,
no_mpls_label_global_block_cmd,
"no mpls label global-block [(16-1048575) (16-1048575)]",
NO_STR
MPLS_STR
"Label configuration\n"
"Configure global label block\n"
"Start label\n"
"End label\n")
{
return zebra_mpls_global_block (vty, 0, NULL, NULL);
}
/* MPLS node for MPLS LSP. */
static struct cmd_node mpls_node = { MPLS_NODE, "", 1 };
@ -876,7 +1094,13 @@ zebra_mpls_vty_init (void)
install_element (CONFIG_NODE, &no_mpls_transit_lsp_cmd);
install_element (CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd);
install_element (CONFIG_NODE, &no_mpls_transit_lsp_all_cmd);
install_element (CONFIG_NODE, &mpls_label_bind_cmd);
install_element (CONFIG_NODE, &no_mpls_label_bind_cmd);
install_element (CONFIG_NODE, &mpls_label_global_block_cmd);
install_element (CONFIG_NODE, &no_mpls_label_global_block_cmd);
install_element (VIEW_NODE, &show_mpls_table_cmd);
install_element (VIEW_NODE, &show_mpls_table_lsp_cmd);
install_element (VIEW_NODE, &show_mpls_fec_cmd);
}

View File

@ -1084,7 +1084,25 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
return rib->nexthop_active_num;
}
/*
* Is this RIB labeled-unicast? It must be of type BGP and all paths
* (nexthops) must have a label.
*/
int
zebra_rib_labeled_unicast (struct rib *rib)
{
struct nexthop *nexthop = NULL, *tnexthop;
int recursing;
if (rib->type != ZEBRA_ROUTE_BGP)
return 0;
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
return 0;
return 1;
}
/* Update flag indicates whether this is a "replace" or not. Currently, this
* is only used for IPv4.
@ -1177,7 +1195,12 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
if (! RIB_SYSTEM_ROUTE (rib))
rib_uninstall_kernel (rn, rib);
UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
/* If labeled-unicast route, uninstall transit LSP. */
if (zebra_rib_labeled_unicast (rib))
zebra_mpls_lsp_uninstall (info->zvrf, rn, rib);
UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
}
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
@ -1272,6 +1295,10 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
zvrf_id (zvrf), buf, rn, new, new->type);
}
/* If labeled-unicast route, install transit LSP. */
if (zebra_rib_labeled_unicast (new))
zebra_mpls_lsp_install (zvrf, rn, new);
if (!RIB_SYSTEM_ROUTE (new))
{
if (rib_install_kernel (rn, new, NULL))
@ -1301,6 +1328,10 @@ rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
zvrf_id (zvrf), buf, rn, old, old->type);
}
/* If labeled-unicast route, uninstall transit LSP. */
if (zebra_rib_labeled_unicast (old))
zebra_mpls_lsp_uninstall (zvrf, rn, old);
if (!RIB_SYSTEM_ROUTE (old))
rib_uninstall_kernel (rn, old);
@ -1354,6 +1385,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
/* Non-system route should be installed. */
if (!RIB_SYSTEM_ROUTE (new))
{
/* If labeled-unicast route, install transit LSP. */
if (zebra_rib_labeled_unicast (new))
zebra_mpls_lsp_install (zvrf, rn, new);
if (rib_install_kernel (rn, new, old))
{
char buf[SRCDEST2STR_BUFFER];
@ -1368,6 +1403,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
{
if (RIB_SYSTEM_ROUTE(new))
{
/* If labeled-unicast route, uninstall transit LSP. */
if (zebra_rib_labeled_unicast (old))
zebra_mpls_lsp_uninstall (zvrf, rn, old);
if (!RIB_SYSTEM_ROUTE (old))
rib_uninstall_kernel (rn, old);
}
@ -1404,6 +1443,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
nh_active ? "install failed" : "nexthop inactive");
}
/* If labeled-unicast route, uninstall transit LSP. */
if (zebra_rib_labeled_unicast (old))
zebra_mpls_lsp_uninstall (zvrf, rn, old);
if (!RIB_SYSTEM_ROUTE (old))
rib_uninstall_kernel (rn, old);
UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB);
@ -2934,8 +2977,10 @@ rib_tables_iter_next (rib_tables_iter_t *iter)
} afi_safis[] = {
{ AFI_IP, SAFI_UNICAST },
{ AFI_IP, SAFI_MULTICAST },
{ AFI_IP, SAFI_LABELED_UNICAST },
{ AFI_IP6, SAFI_UNICAST },
{ AFI_IP6, SAFI_MULTICAST },
{ AFI_IP6, SAFI_LABELED_UNICAST },
};
table = NULL;

View File

@ -25,6 +25,13 @@
#include <zebra/zebra_ns.h>
/* MPLS (Segment Routing) global block */
typedef struct mpls_srgb_t_
{
u_int32_t start_label;
u_int32_t end_label;
} mpls_srgb_t;
/* Routing table instance. */
struct zebra_vrf
{
@ -79,6 +86,12 @@ struct zebra_vrf
/* MPLS label forwarding table */
struct hash *lsp_table;
/* MPLS FEC binding table */
struct route_table *fec_table[AFI_MAX];
/* MPLS Segment Routing Global block */
mpls_srgb_t mpls_srgb;
/* MPLS processing flags */
u_int16_t mpls_flags;
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)

View File

@ -934,6 +934,109 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
return 0;
}
#define ZEBRA_MIN_FEC_LENGTH 9
/* FEC register */
static int
zserv_fec_register (struct zserv *client, int sock, u_short length)
{
struct stream *s;
struct zebra_vrf *zvrf;
u_short l = 0;
struct prefix p;
u_int16_t flags;
u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
s = client->ibuf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return 0; // unexpected
/*
* The minimum amount of data that can be sent for one fec
* registration
*/
if (length < ZEBRA_MIN_FEC_LENGTH)
{
zlog_err ("fec_register: Received a fec register of length %d, it is of insufficient size to properly decode",
length);
return -1;
}
while (l < length)
{
flags = stream_getw(s);
p.family = stream_getw(s);
if (p.family != AF_INET &&
p.family != AF_INET6)
{
zlog_err ("fec_register: Received unknown family type %d\n",
p.family);
return -1;
}
p.prefixlen = stream_getc(s);
l += 5;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX)
{
label_index = stream_getl(s);
l += 4;
}
zebra_mpls_fec_register (zvrf, &p, label_index, client);
}
return 0;
}
/* FEC unregister */
static int
zserv_fec_unregister (struct zserv *client, int sock, u_short length)
{
struct stream *s;
struct zebra_vrf *zvrf;
u_short l = 0;
struct prefix p;
//u_int16_t flags;
s = client->ibuf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return 0; // unexpected
/*
* The minimum amount of data that can be sent for one
* fec unregistration
*/
if (length < ZEBRA_MIN_FEC_LENGTH)
{
zlog_err ("fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode",
length);
return -1;
}
while (l < length)
{
//flags = stream_getw(s);
(void)stream_getw(s);
p.family = stream_getw(s);
if (p.family != AF_INET &&
p.family != AF_INET6)
{
zlog_err ("fec_unregister: Received unknown family type %d\n",
p.family);
return -1;
}
p.prefixlen = stream_getc(s);
l += 5;
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
zebra_mpls_fec_unregister (zvrf, &p, client);
}
return 0;
}
/*
Modified version of zsend_ipv4_nexthop_lookup():
Query unicast rib if nexthop is not found on mrib.
@ -1075,13 +1178,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
struct rib *rib;
struct prefix p;
u_char message;
struct in_addr nexthop;
struct in_addr nhop_addr;
u_char nexthop_num;
u_char nexthop_type;
struct stream *s;
ifindex_t ifindex;
safi_t safi;
int ret;
mpls_label_t label;
struct nexthop *nexthop;
/* Get input stream. */
s = client->ibuf;
@ -1123,13 +1228,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
rib_nexthop_ifindex_add (rib, ifindex);
break;
case NEXTHOP_TYPE_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
rib_nexthop_ipv4_add (rib, &nexthop, NULL);
nhop_addr.s_addr = stream_get_ipv4 (s);
nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL);
/* For labeled-unicast, each nexthop is followed by label. */
if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
{
label = (mpls_label_t)stream_getl (s);
nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label);
}
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
nexthop.s_addr = stream_get_ipv4 (s);
nhop_addr.s_addr = stream_get_ipv4 (s);
ifindex = stream_getl (s);
rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex);
break;
case NEXTHOP_TYPE_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
@ -1222,6 +1333,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
break;
case NEXTHOP_TYPE_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
/* For labeled-unicast, each nexthop is followed by label, but
* we don't care for delete.
*/
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
stream_forward_getp (s, sizeof(u_int32_t));
nexthop_p = (union g_addr *)&nexthop;
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
@ -1407,7 +1523,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
unsigned int i;
struct stream *s;
struct in6_addr nexthop;
struct in6_addr nhop_addr;
struct rib *rib;
u_char message;
u_char nexthop_num;
@ -1418,11 +1534,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
static struct in6_addr nexthops[MULTIPATH_NUM];
static unsigned int ifindices[MULTIPATH_NUM];
int ret;
static mpls_label_t labels[MULTIPATH_NUM];
mpls_label_t label;
struct nexthop *nexthop;
/* Get input stream. */
s = client->ibuf;
memset (&nexthop, 0, sizeof (struct in6_addr));
memset (&nhop_addr, 0, sizeof (struct in6_addr));
/* Allocate new rib. */
rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
@ -1471,10 +1590,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
switch (nexthop_type)
{
case NEXTHOP_TYPE_IPV6:
stream_get (&nexthop, s, 16);
if (nh_count < multipath_num) {
nexthops[nh_count++] = nexthop;
}
stream_get (&nhop_addr, s, 16);
if (nh_count < MULTIPATH_NUM)
{
/* For labeled-unicast, each nexthop is followed by label. */
if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
{
label = (mpls_label_t)stream_getl (s);
labels[nh_count++] = label;
}
nexthops[nh_count++] = nhop_addr;
}
break;
case NEXTHOP_TYPE_IFINDEX:
if (if_count < multipath_num) {
@ -1492,9 +1618,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
if ((i < if_count) && ifindices[i])
rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
else
rib_nexthop_ipv6_add (rib, &nexthops[i]);
nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]);
if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]);
}
else {
if ((i < if_count) && ifindices[i])
@ -1591,6 +1719,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
{
case NEXTHOP_TYPE_IPV6:
stream_get (&nexthop, s, 16);
/* For labeled-unicast, each nexthop is followed by label, but
* we don't care for delete.
*/
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
stream_forward_getp (s, sizeof(u_int32_t));
pnexthop = (union g_addr *)&nexthop;
break;
case NEXTHOP_TYPE_IFINDEX:
@ -1761,14 +1894,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
if (command == ZEBRA_MPLS_LABELS_ADD)
{
mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
NULL, ifindex);
ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
}
else if (command == ZEBRA_MPLS_LABELS_DELETE)
{
mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex);
mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex);
if (out_label != MPLS_IMP_NULL_LABEL)
mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex,
distance, out_label);
@ -1975,6 +2108,9 @@ zebra_client_close (struct zserv *client)
/* Release Label Manager chunks */
release_daemon_chunks (client->proto, client->instance);
/* Cleanup any FECs registered by this client. */
zebra_mpls_cleanup_fecs_for_client (vrf_info_lookup(VRF_DEFAULT), client);
/* Close file descriptor. */
if (client->sock)
{
@ -2263,6 +2399,12 @@ zebra_client_read (struct thread *thread)
case ZEBRA_RELEASE_LABEL_CHUNK:
zread_label_manager_request (command, client, vrf_id);
break;
case ZEBRA_FEC_REGISTER:
zserv_fec_register (client, sock, length);
break;
case ZEBRA_FEC_UNREGISTER:
zserv_fec_unregister (client, sock, length);
break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;