mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-10 16:42:44 +00:00
Merge branch 'master' into EIGRP
This commit is contained in:
commit
b46be72b4a
@ -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@
|
||||
|
@ -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);
|
||||
|
@ -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)) ? \
|
||||
|
@ -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
|
||||
|
@ -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
338
bgpd/bgp_label.c
Normal 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
125
bgpd/bgp_label.h
Normal 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 */
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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])
|
||||
|
@ -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:
|
||||
|
381
bgpd/bgp_route.c
381
bgpd/bgp_route.c
@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "thread.h"
|
||||
#include "workqueue.h"
|
||||
#include "queue.h"
|
||||
#include "mpls.h"
|
||||
#include "memory.h"
|
||||
#include "lib/json.h"
|
||||
|
||||
@ -62,6 +63,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "bgpd/bgp_mpath.h"
|
||||
#include "bgpd/bgp_nht.h"
|
||||
#include "bgpd/bgp_updgrp.h"
|
||||
#include "bgpd/bgp_label.h"
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
301
bgpd/bgp_vty.c
301
bgpd/bgp_vty.c
@ -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);
|
||||
|
@ -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" \
|
||||
|
157
bgpd/bgp_zebra.c
157
bgpd/bgp_zebra.c
@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "lib/json.h"
|
||||
#include "lib/bfd.h"
|
||||
#include "filter.h"
|
||||
#include "mpls.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_route.h"
|
||||
@ -46,6 +47,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "bgpd/bgp_nexthop.h"
|
||||
#include "bgpd/bgp_nht.h"
|
||||
#include "bgpd/bgp_bfd.h"
|
||||
#include "bgpd/bgp_label.h"
|
||||
#if ENABLE_BGP_VNC
|
||||
# include "bgpd/rfapi/rfapi_backend.h"
|
||||
# include "bgpd/rfapi/vnc_export_bgp.h"
|
||||
@ -57,6 +59,7 @@ struct zclient *zclient = NULL;
|
||||
/* Growable buffer for nexthops sent to zebra */
|
||||
struct stream *bgp_nexthop_buf = NULL;
|
||||
struct stream *bgp_ifindices_buf = NULL;
|
||||
struct stream *bgp_label_buf = NULL;
|
||||
|
||||
/* These array buffers are used in making a copy of the attributes for
|
||||
route-map apply. Arrays are being used here to minimize mallocs and
|
||||
@ -178,6 +181,14 @@ bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bgp_read_fec_update (int command, struct zclient *zclient,
|
||||
zebra_size_t length)
|
||||
{
|
||||
bgp_parse_fec_update();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp)
|
||||
{
|
||||
@ -1204,8 +1215,8 @@ bgp_table_map_apply (struct route_map *map, struct prefix *p,
|
||||
}
|
||||
|
||||
void
|
||||
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
afi_t afi, safi_t safi)
|
||||
bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info,
|
||||
struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
{
|
||||
u_int32_t flags;
|
||||
u_char distance;
|
||||
@ -1216,6 +1227,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
struct bgp_info local_info;
|
||||
struct bgp_info *info_cp = &local_info;
|
||||
route_tag_t tag;
|
||||
u_int32_t label;
|
||||
|
||||
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
|
||||
* know of this instance.
|
||||
@ -1271,7 +1283,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
|
||||
(sizeof (struct in_addr *) * nhcount))
|
||||
{
|
||||
newsize = (sizeof (struct in_addr *) * nhcount);
|
||||
newsize = sizeof (struct in_addr *) * nhcount;
|
||||
newsize = stream_resize (bgp_nexthop_buf, newsize);
|
||||
if (newsize == oldsize)
|
||||
{
|
||||
@ -1282,6 +1294,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
stream_reset (bgp_nexthop_buf);
|
||||
nexthop = NULL;
|
||||
|
||||
/* For labeled unicast, each nexthop has a label too. Resize label
|
||||
* buffer, if required.
|
||||
*/
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
if ((oldsize = stream_get_size (bgp_label_buf)) <
|
||||
(sizeof (unsigned int) * nhcount))
|
||||
{
|
||||
newsize = (sizeof (unsigned int) * nhcount);
|
||||
newsize = stream_resize (bgp_label_buf, newsize);
|
||||
if (newsize == oldsize)
|
||||
{
|
||||
zlog_err ("can't resize label buffer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream_reset (bgp_label_buf);
|
||||
}
|
||||
|
||||
/* Metric is currently based on the best-path only. */
|
||||
metric = info->attr->med;
|
||||
|
||||
@ -1311,6 +1342,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
{
|
||||
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
|
||||
valid_nh_count++;
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
label = label_pton(info->extra->tag);
|
||||
stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
|
||||
}
|
||||
}
|
||||
|
||||
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
|
||||
@ -1336,6 +1372,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
continue;
|
||||
|
||||
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
label = label_pton(mpinfo->extra->tag);
|
||||
stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
|
||||
}
|
||||
valid_nh_count++;
|
||||
}
|
||||
|
||||
@ -1344,8 +1385,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.instance = 0;
|
||||
api.message = 0;
|
||||
api.safi = safi;
|
||||
api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
|
||||
|
||||
/* Note that this currently only applies to Null0 routes for aggregates.
|
||||
* ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a special
|
||||
@ -1358,6 +1401,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
api.nexthop_num = valid_nh_count;
|
||||
|
||||
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
api.label_num = valid_nh_count;
|
||||
api.label = (unsigned int *)STREAM_DATA (bgp_label_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
api.label_num = 0;
|
||||
api.label = NULL;
|
||||
}
|
||||
api.ifindex_num = 0;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
|
||||
api.metric = metric;
|
||||
@ -1379,14 +1432,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
if (bgp_debug_zebra(p))
|
||||
{
|
||||
int i;
|
||||
char label_buf[20];
|
||||
zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI
|
||||
" count %d", (valid_nh_count ? "add":"delete"),
|
||||
bgp->vrf_id,
|
||||
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
|
||||
p->prefixlen, api.metric, api.tag, api.nexthop_num);
|
||||
for (i = 0; i < api.nexthop_num; i++)
|
||||
zlog_debug(" IPv4 [nexthop %d] %s", i+1,
|
||||
inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
|
||||
{
|
||||
label_buf[0] = '\0';
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
sprintf(label_buf, "label %u", api.label[i]);
|
||||
zlog_debug(" nhop [%d]: %s %s",
|
||||
i+1,
|
||||
inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])),
|
||||
label_buf);
|
||||
}
|
||||
}
|
||||
|
||||
zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
|
||||
@ -1431,6 +1492,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
}
|
||||
stream_reset (bgp_ifindices_buf);
|
||||
|
||||
/* For labeled unicast, each nexthop has a label too. Resize label
|
||||
* buffer, if required.
|
||||
*/
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
if ((oldsize = stream_get_size (bgp_label_buf)) <
|
||||
(sizeof (unsigned int) * nhcount))
|
||||
{
|
||||
newsize = (sizeof (unsigned int) * nhcount);
|
||||
newsize = stream_resize (bgp_label_buf, newsize);
|
||||
if (newsize == oldsize)
|
||||
{
|
||||
zlog_err ("can't resize label buffer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream_reset (bgp_label_buf);
|
||||
}
|
||||
|
||||
ifindex = 0;
|
||||
nexthop = NULL;
|
||||
|
||||
@ -1476,6 +1556,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
}
|
||||
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
|
||||
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
label = label_pton(info->extra->tag);
|
||||
stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
|
||||
}
|
||||
valid_nh_count++;
|
||||
}
|
||||
|
||||
@ -1518,6 +1603,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
|
||||
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
|
||||
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
label = label_pton(mpinfo->extra->tag);
|
||||
stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
|
||||
}
|
||||
valid_nh_count++;
|
||||
}
|
||||
|
||||
@ -1527,8 +1617,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.instance = 0;
|
||||
api.message = 0;
|
||||
api.safi = safi;
|
||||
api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
|
||||
|
||||
/* Note that this currently only applies to Null0 routes for aggregates.
|
||||
* ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a special
|
||||
@ -1544,6 +1636,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
|
||||
api.ifindex_num = valid_nh_count;
|
||||
api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
{
|
||||
api.label_num = valid_nh_count;
|
||||
api.label = (unsigned int *)STREAM_DATA (bgp_label_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
api.label_num = 0;
|
||||
api.label = NULL;
|
||||
}
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
|
||||
api.metric = metric;
|
||||
api.tag = 0;
|
||||
@ -1566,13 +1668,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
if (bgp_debug_zebra(p))
|
||||
{
|
||||
int i;
|
||||
char label_buf[20];
|
||||
zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
|
||||
valid_nh_count ? "add" : "delete", bgp->vrf_id,
|
||||
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
|
||||
p->prefixlen, api.metric, api.tag);
|
||||
for (i = 0; i < api.nexthop_num; i++)
|
||||
zlog_debug(" IPv6 [nexthop %d] %s", i+1,
|
||||
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
|
||||
{
|
||||
label_buf[0] = '\0';
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
sprintf(label_buf, "label %u", api.label[i]);
|
||||
zlog_debug(" nhop [%d]: %s if %s %s",
|
||||
i+1,
|
||||
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
|
||||
ifindex2ifname (api.ifindex[i], bgp->vrf_id),
|
||||
label_buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_nh_count)
|
||||
@ -1588,13 +1699,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
|
||||
if (bgp_debug_zebra(p))
|
||||
{
|
||||
int i;
|
||||
char label_buf[20];
|
||||
zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
|
||||
valid_nh_count ? "add" : "delete", bgp->vrf_id,
|
||||
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
|
||||
p->prefixlen, api.metric, api.tag);
|
||||
for (i = 0; i < api.nexthop_num; i++)
|
||||
zlog_debug(" IPv6 [nexthop %d] %s", i+1,
|
||||
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
|
||||
{
|
||||
label_buf[0] = '\0';
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
sprintf(label_buf, "label %u", api.label[i]);
|
||||
zlog_debug(" nhop [%d]: %s if %s %s",
|
||||
i+1,
|
||||
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
|
||||
ifindex2ifname (api.ifindex[i], bgp->vrf_id),
|
||||
label_buf);
|
||||
}
|
||||
}
|
||||
|
||||
zapi_ipv6_route (valid_nh_count ?
|
||||
@ -1626,7 +1746,7 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
|
||||
&& ri->type == ZEBRA_ROUTE_BGP
|
||||
&& ri->sub_type == BGP_ROUTE_NORMAL)
|
||||
bgp_zebra_announce (&rn->p, ri, bgp, afi, safi);
|
||||
bgp_zebra_announce (rn, &rn->p, ri, bgp, afi, safi);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1673,10 +1793,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.instance = 0;
|
||||
api.message = 0;
|
||||
api.safi = safi;
|
||||
api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
|
||||
api.nexthop_num = 0;
|
||||
api.nexthop = NULL;
|
||||
api.label_num = 0;
|
||||
api.label = NULL;
|
||||
api.ifindex_num = 0;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
|
||||
api.metric = info->attr->med;
|
||||
@ -1712,11 +1836,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.instance = 0;
|
||||
api.message = 0;
|
||||
api.safi = safi;
|
||||
api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
|
||||
api.nexthop_num = 0;
|
||||
api.nexthop = NULL;
|
||||
api.ifindex_num = 0;
|
||||
api.label_num = 0;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
|
||||
api.metric = info->attr->med;
|
||||
api.tag = 0;
|
||||
@ -2141,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
|
||||
|
@ -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);
|
||||
|
||||
|
18
bgpd/bgpd.c
18
bgpd/bgpd.c
@ -1636,6 +1636,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST],
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP],
|
||||
@ -1644,6 +1646,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST],
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST],
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN],
|
||||
PEER_FLAG_REFLECTOR_CLIENT);
|
||||
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
|
||||
@ -3608,10 +3612,12 @@ peer_active (struct peer *peer)
|
||||
return 0;
|
||||
if (peer->afc[AFI_IP][SAFI_UNICAST]
|
||||
|| peer->afc[AFI_IP][SAFI_MULTICAST]
|
||||
|| peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
|
||||
|| peer->afc[AFI_IP][SAFI_MPLS_VPN]
|
||||
|| peer->afc[AFI_IP][SAFI_ENCAP]
|
||||
|| peer->afc[AFI_IP6][SAFI_UNICAST]
|
||||
|| peer->afc[AFI_IP6][SAFI_MULTICAST]
|
||||
|| peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
|
||||
|| peer->afc[AFI_IP6][SAFI_MPLS_VPN]
|
||||
|| peer->afc[AFI_IP6][SAFI_ENCAP])
|
||||
return 1;
|
||||
@ -3624,10 +3630,12 @@ peer_active_nego (struct peer *peer)
|
||||
{
|
||||
if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
|
||||
|| peer->afc_nego[AFI_IP][SAFI_MULTICAST]
|
||||
|| peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
|
||||
|| peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
|
||||
|| peer->afc_nego[AFI_IP][SAFI_ENCAP]
|
||||
|| peer->afc_nego[AFI_IP6][SAFI_UNICAST]
|
||||
|| peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
|
||||
|| peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
|
||||
|| peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
|
||||
|| peer->afc_nego[AFI_IP6][SAFI_ENCAP])
|
||||
return 1;
|
||||
@ -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);
|
||||
|
||||
|
14
bgpd/bgpd.h
14
bgpd/bgpd.h
@ -76,6 +76,8 @@ enum bgp_af_index
|
||||
BGP_AF_IPV4_ENCAP,
|
||||
BGP_AF_IPV6_ENCAP,
|
||||
BGP_AF_L2VPN_EVPN,
|
||||
BGP_AF_IPV4_LBL_UNICAST,
|
||||
BGP_AF_IPV6_LBL_UNICAST,
|
||||
BGP_AF_MAX
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
@ -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
1
debian/frr.dirs
vendored
@ -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
1
debian/frr.install
vendored
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
424
isisd/isis_lsp.c
424
isisd/isis_lsp.c
@ -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);
|
||||
|
@ -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
724
isisd/isis_mt.c
Normal 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
146
isisd/isis_mt.h
Normal 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
|
@ -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)
|
||||
|
@ -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)
|
||||
|
720
isisd/isis_spf.c
720
isisd/isis_spf.c
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
685
isisd/isis_tlv.c
685
isisd/isis_tlv.c
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
10
ldpd/lde.c
10
ldpd/lde.c
@ -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
|
||||
|
10
ldpd/ldpe.c
10
ldpd/ldpe.c
@ -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 */
|
||||
|
@ -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 = \
|
||||
|
@ -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:
|
||||
|
@ -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
184
lib/frr_pthread.c
Normal 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
145
lib/frr_pthread.h
Normal 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 */
|
@ -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 *
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
||||
|
25
lib/stream.c
25
lib/stream.c
@ -919,6 +919,31 @@ stream_put_prefix (struct stream *s, struct prefix *p)
|
||||
return stream_put_prefix_addpath (s, p, 0, 0);
|
||||
}
|
||||
|
||||
/* Put NLRI with label */
|
||||
int
|
||||
stream_put_labeled_prefix (struct stream *s, struct prefix *p, u_char *label)
|
||||
{
|
||||
size_t psize;
|
||||
|
||||
STREAM_VERIFY_SANE(s);
|
||||
|
||||
psize = PSIZE (p->prefixlen);
|
||||
|
||||
if (STREAM_WRITEABLE (s) < (psize + 3))
|
||||
{
|
||||
STREAM_BOUND_WARN (s, "put");
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream_putc (s, (p->prefixlen + 24));
|
||||
stream_putc(s, label[0]);
|
||||
stream_putc(s, label[1]);
|
||||
stream_putc(s, label[2]);
|
||||
memcpy (s->data + s->endp, &p->u.prefix, psize);
|
||||
s->endp += psize;
|
||||
|
||||
return (psize + 3);
|
||||
}
|
||||
|
||||
/* Read size from fd. */
|
||||
int
|
||||
|
@ -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 *);
|
||||
|
377
lib/thread.c
377
lib/thread.c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
11
lib/zebra.h
11
lib/zebra.h
@ -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;
|
||||
}
|
||||
|
||||
|
8
tools/etc/iproute2/rt_protos.d/frr.conf
Normal file
8
tools/etc/iproute2/rt_protos.d/frr.conf
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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}
|
||||
};
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
1092
zebra/zebra_mpls.c
1092
zebra/zebra_mpls.c
File diff suppressed because it is too large
Load Diff
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
172
zebra/zserv.c
172
zebra/zserv.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user