Merge branch 'master' into docs-user

Manually merged these doc commits:

3bb7cd7f56
ff21655441
This commit is contained in:
Quentin Young 2018-01-30 15:05:15 -05:00
commit d38549c99d
No known key found for this signature in database
GPG Key ID: DAF48E0F57E0834F
214 changed files with 17636 additions and 3532 deletions

View File

@ -57,3 +57,5 @@ ForEachMacros:
- SUBGRP_FOREACH_ADJ_SAFE
- AF_FOREACH
- FOREACH_AFI_SAFI
# ospfd
- LSDB_LOOP

View File

@ -68,6 +68,16 @@ Italicized lists are private.
| _Security_ | security@lists.frrouting.org |
| _Technical Steering Committee_ | tsc@lists.frrouting.org |
The Development list is used to discuss and document general issues
related to project development and governance. The public Slack
instance, frrouting.slack.com, and weekly technical meetings provide a
higher bandwidth channel for discussions. The results of such
discussions must be reflected in updates, as appropriate, to code (i.e.,
merges), [github](https://github.com/FRRouting/frr/issues) tracked
issues, and for governance or process changes, updates to the
Development list and either this file or information posted at
[https://frrouting.org/](https://frrouting.org/).
### Changelog

12
README
View File

@ -1,12 +1,14 @@
FRRouting is free software that manages various IPv4 and IPv6 routing
protocols.
FRRouting is free software that implements and manages various IPv4 and IPv6
routing protocols.
Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1,
RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS,
EIGRP and NHRP.
Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng,
IS-IS, PIM-SM/MSDP, LDP and Babel as well as very early support for EIGRP and
NHRP.
See the file REPORTING-BUGS to report bugs.
See COMMUNITY.md for information on contributing.
Free RRRouting is free software. See the file COPYING for copying conditions.
Public email discussion can be found at https://lists.frrouting.org/listinfo

View File

@ -229,7 +229,7 @@ babel_get_myid(void)
int ifindex = if_nametoindex(ifp->name);
if(ifindex > 0) {
unsigned char eui[8];
rc = if_eui64(ifp->name, ifindex, eui);
rc = if_eui64(ifindex, eui);
if(rc < 0)
continue;
memcpy(myid, eui, 8);
@ -245,7 +245,7 @@ babel_get_myid(void)
ifname = if_indextoname(i, buf);
if(ifname == NULL)
continue;
rc = if_eui64(ifname, i, eui);
rc = if_eui64(i, eui);
if(rc < 0)
continue;
memcpy(myid, eui, 8);

View File

@ -166,6 +166,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
api.type = ZEBRA_ROUTE_BABEL;
api.safi = SAFI_UNICAST;
api.vrf_id = VRF_DEFAULT;
api.nh_vrf_id = VRF_DEFAULT;
api.prefix = quagga_prefix;
if(metric >= KERNEL_INFINITY) {
@ -203,7 +204,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
}
int
if_eui64(char *ifname, int ifindex, unsigned char *eui)
if_eui64(int ifindex, unsigned char *eui)
{
struct interface *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
if (ifp == NULL) {

View File

@ -40,7 +40,7 @@ int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex,
unsigned int newmetric);
int if_eui64(char *ifname, int ifindex, unsigned char *eui);
int if_eui64(int ifindex, unsigned char *eui);
int gettime(struct timeval *tv);
int read_random_bytes(void *buf, size_t len);

View File

@ -133,6 +133,7 @@ dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 \
bgpd.conf.vnc.sample
bgp_vty.o: bgp_vty_clippy.c
bgp_route.o: bgp_route_clippy.c
EXTRA_DIST = BGP4-MIB.txt

View File

@ -246,8 +246,6 @@ void bgp_sync_init(struct peer *peer)
BGP_ADV_FIFO_INIT(&sync->withdraw);
BGP_ADV_FIFO_INIT(&sync->withdraw_low);
peer->sync[afi][safi] = sync;
peer->hash[afi][safi] = hash_create(baa_hash_key, baa_hash_cmp,
"BGP Sync Hash");
}
}
@ -260,9 +258,5 @@ void bgp_sync_delete(struct peer *peer)
if (peer->sync[afi][safi])
XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
peer->sync[afi][safi] = NULL;
if (peer->hash[afi][safi])
hash_free(peer->hash[afi][safi]);
peer->hash[afi][safi] = NULL;
}
}

View File

@ -74,6 +74,7 @@ static const struct message attr_str[] = {
{BGP_ATTR_AS4_PATH, "AS4_PATH"},
{BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR"},
{BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT"},
{BGP_ATTR_PMSI_TUNNEL, "PMSI_TUNNEL_ATTRIBUTE"},
{BGP_ATTR_ENCAP, "ENCAP"},
#if ENABLE_BGP_VNC
{BGP_ATTR_VNC, "VNC"},
@ -492,19 +493,13 @@ unsigned int attrhash_key_make(void *p)
const struct attr *attr = (struct attr *)p;
uint32_t key = 0;
#define MIX(val) key = jhash_1word(val, key)
#define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
MIX(attr->origin);
MIX(attr->nexthop.s_addr);
MIX(attr->med);
MIX(attr->local_pref);
MIX(attr->aggregator_as);
MIX(attr->aggregator_addr.s_addr);
MIX(attr->weight);
MIX(attr->mp_nexthop_global_in.s_addr);
MIX(attr->originator_id.s_addr);
MIX(attr->tag);
MIX(attr->label);
MIX(attr->label_index);
MIX3(attr->origin, attr->nexthop.s_addr, attr->med);
MIX3(attr->local_pref, attr->aggregator_as, attr->aggregator_addr.s_addr);
MIX3(attr->weight, attr->mp_nexthop_global_in.s_addr,
attr->originator_id.s_addr);
MIX3(attr->tag, attr->label, attr->label_index);
if (attr->aspath)
MIX(aspath_key_make(attr->aspath));
@ -550,12 +545,6 @@ int attrhash_cmp(const void *p1, const void *p2)
&& attr1->tag == attr2->tag
&& attr1->label_index == attr2->label_index
&& attr1->mp_nexthop_len == attr2->mp_nexthop_len
&& IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
&attr2->mp_nexthop_global)
&& IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
&attr2->mp_nexthop_local)
&& IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
&attr2->mp_nexthop_global_in)
&& attr1->ecommunity == attr2->ecommunity
&& attr1->lcommunity == attr2->lcommunity
&& attr1->cluster == attr2->cluster
@ -565,6 +554,12 @@ int attrhash_cmp(const void *p1, const void *p2)
#if ENABLE_BGP_VNC
&& encap_same(attr1->vnc_subtlvs, attr2->vnc_subtlvs)
#endif
&& IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
&attr2->mp_nexthop_global)
&& IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
&attr2->mp_nexthop_local)
&& IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
&attr2->mp_nexthop_global_in)
&& IPV4_ADDR_SAME(&attr1->originator_id,
&attr2->originator_id)
&& overlay_index_same(attr1, attr2))
@ -1040,6 +1035,8 @@ const u_int8_t attr_flags_values[] = {
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_AGGREGATOR] =
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_PMSI_TUNNEL] =
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_LARGE_COMMUNITIES] =
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_PREFIX_SID] =
@ -1879,6 +1876,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
attr->sticky = sticky;
/* Extract the Rmac, if any */
bgp_attr_rmac(attr, &attr->rmac);
return BGP_ATTR_PARSE_PROCEED;
}
@ -3252,6 +3252,17 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
#endif
}
/* PMSI Tunnel */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
stream_putc(s, 9); // Length
stream_putc(s, 0); // Flags
stream_putc(s, 6); // Tunnel type: Ingress Replication (6)
stream_put(s, &(attr->label), BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
stream_put_ipv4(s, attr->nexthop.s_addr); // Unicast tunnel endpoint IP address
}
/* Unknown transit attribute. */
if (attr->transit)
stream_put(s, attr->transit->val, attr->transit->length);

View File

@ -182,6 +182,9 @@ struct attr {
/* EVPN MAC Mobility sequence number, if any. */
u_int32_t mm_seqnum;
/* EVPN local router-mac */
struct ethaddr rmac;
};
/* rmap_change_flags definition */

View File

@ -105,6 +105,35 @@ char *ecom_mac2str(char *ecom_mac)
return prefix_mac2str((struct ethaddr *)en, NULL, 0);
}
/* Fetch router-mac from extended community */
void bgp_attr_rmac(struct attr *attr,
struct ethaddr *rmac)
{
int i = 0;
struct ecommunity *ecom;
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
return;
/* If there is a router mac extended community, set RMAC in attr */
for (i = 0; i < ecom->size; i++) {
u_char *pnt = NULL;
u_char type = 0;
u_char sub_type = 0;
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
type = *pnt++;
sub_type = *pnt++;
if (!(type == ECOMMUNITY_ENCODE_EVPN &&
sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
continue;
memcpy(rmac, pnt, ETH_ALEN);
}
}
/*
* Fetch and return the sequence number from MAC Mobility extended
* community, if present, else 0.

View File

@ -59,7 +59,7 @@ extern void bgp_add_routermac_ecom(struct attr *attr,
struct ethaddr *routermac);
extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
struct prefix *dst);
extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
extern u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
u_char *sticky);

View File

@ -302,13 +302,13 @@ static int bgp_bfd_dest_update(int command, struct zclient *zclient,
prefix2str(&dp, buf[0], sizeof(buf[0]));
if (ifp) {
zlog_debug(
"Zebra: vrf %d interface %s bfd destination %s %s",
"Zebra: vrf %u interface %s bfd destination %s %s",
vrf_id, ifp->name, buf[0],
bfd_get_status_str(status));
} else {
prefix2str(&sp, buf[1], sizeof(buf[1]));
zlog_debug(
"Zebra: vrf %d source %s bfd destination %s %s",
"Zebra: vrf %u source %s bfd destination %s %s",
vrf_id, buf[1], buf[0],
bfd_get_status_str(status));
}

View File

@ -695,19 +695,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
} else if (type == ECOMMUNITY_ENCODE_EVPN) {
if (filter == ECOMMUNITY_ROUTE_TARGET)
continue;
if (*pnt == ECOMMUNITY_SITE_ORIGIN) {
char macaddr[6];
if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC) {
struct ethaddr rmac;
pnt++;
memcpy(&macaddr, pnt, 6);
memcpy(&rmac, pnt, ETH_ALEN);
len = sprintf(
str_buf + str_pnt,
"EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
(uint8_t)macaddr[0],
(uint8_t)macaddr[1],
(uint8_t)macaddr[2],
(uint8_t)macaddr[3],
(uint8_t)macaddr[4],
(uint8_t)macaddr[5]);
"Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
(uint8_t)rmac.octet[0],
(uint8_t)rmac.octet[1],
(uint8_t)rmac.octet[2],
(uint8_t)rmac.octet[3],
(uint8_t)rmac.octet[4],
(uint8_t)rmac.octet[5]);
} else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
u_int32_t seqnum;

File diff suppressed because it is too large Load Diff

View File

@ -22,9 +22,29 @@
#define _QUAGGA_BGP_EVPN_H
#include "vxlan.h"
#include "bgpd.h"
#define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
static inline int is_evpn_enabled(void)
{
struct bgp *bgp = NULL;
bgp = bgp_get_default();
return bgp ? bgp->advertise_all_vni : 0;
}
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
struct bgp_node *rn,
afi_t afi, safi_t safi);
extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
struct bgp_node *rn,
afi_t afi, safi_t safi);
extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
safi_t safi);
extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
safi_t safi);
extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf);
extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len);
extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
@ -45,9 +65,14 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
u_char flags);
extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct ethaddr *rmac,
struct in_addr originator_ip);
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip);
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id);
extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
extern void bgp_evpn_cleanup(struct bgp *bgp);
extern void bgp_evpn_init(struct bgp *bgp);

View File

@ -30,9 +30,10 @@
#define RT_ADDRSTRLEN 28
/* EVPN prefix lengths. */
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
#define EVPN_TYPE_2_ROUTE_PREFIXLEN 224
#define EVPN_TYPE_3_ROUTE_PREFIXLEN 224
#define EVPN_TYPE_5_ROUTE_PREFIXLEN 224
/* EVPN route types. */
typedef enum {
@ -53,6 +54,7 @@ typedef enum {
*/
struct bgpevpn {
vni_t vni;
vrf_id_t tenant_vrf_id;
u_int32_t flags;
#define VNI_FLAG_CFGD 0x1 /* VNI is user configured */
#define VNI_FLAG_LIVE 0x2 /* VNI is "live" */
@ -96,10 +98,99 @@ struct irt_node {
struct list *vnis;
};
/* Mapping of Import RT to VRFs.
* The Import RTs of all VRFss are maintained in a hash table with each
* RT linking to all VRFs that will import routes matching this RT.
*/
struct vrf_irt_node {
/* RT */
struct ecommunity_val rt;
/* List of VNIs importing routes matching this RT. */
struct list *vrfs;
};
#define RT_TYPE_IMPORT 1
#define RT_TYPE_EXPORT 2
#define RT_TYPE_BOTH 3
static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
{
return (CHECK_FLAG(bgp_vrf->vrf_flags,
BGP_VRF_RD_CFGD));
}
static inline int bgp_evpn_vrf_rd_matches_existing(struct bgp *bgp_vrf,
struct prefix_rd *prd)
{
return (memcmp(&bgp_vrf->vrf_prd.val, prd->val, ECOMMUNITY_SIZE) == 0);
}
static inline vni_t bgpevpn_get_l3vni(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf)
return 0;
return bgp_vrf->l3vni;
}
static inline void bgpevpn_get_rmac(struct bgpevpn *vpn, struct ethaddr *rmac)
{
struct bgp *bgp_vrf = NULL;
memset(rmac, 0, sizeof(struct ethaddr));
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf)
return;
memcpy(rmac, &bgp_vrf->rmac, sizeof(struct ethaddr));
}
static inline struct list *bgpevpn_get_vrf_export_rtl(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf)
return NULL;
return bgp_vrf->vrf_export_rtl;
}
static inline struct list *bgpevpn_get_vrf_import_rtl(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf)
return NULL;
return bgp_vrf->vrf_import_rtl;
}
static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf || !bgp_vrf->l2vnis)
return;
listnode_delete(bgp_vrf->l2vnis, vpn);
}
static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
{
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
if (!bgp_vrf || !bgp_vrf->l2vnis)
return;
listnode_add_sort(bgp_vrf->l2vnis, vpn);
}
static inline int is_vni_configured(struct bgpevpn *vpn)
{
return (CHECK_FLAG(vpn->flags, VNI_FLAG_CFGD));
@ -157,6 +248,15 @@ static inline vni_t label2vni(mpls_label_t *label)
return vni;
}
static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
struct ethaddr *rmac)
{
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
memcpy(&eval->val[2], rmac, ETH_ALEN);
}
static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
struct ecommunity_val *eval)
{
@ -171,6 +271,44 @@ static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
eval->val[7] = seq & 0xff;
}
static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp,
struct prefix *ip)
{
memset(ip, 0, sizeof(struct prefix));
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
ip->family = AF_INET;
ip->prefixlen = evp->prefix.ip_prefix_length;
memcpy(&(ip->u.prefix4),
&(evp->prefix.ip.ip),
IPV4_MAX_BYTELEN);
} else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
ip->family = AF_INET6;
ip->prefixlen = evp->prefix.ip_prefix_length;
memcpy(&(ip->u.prefix6),
&(evp->prefix.ip.ip),
IPV6_MAX_BYTELEN);
}
}
static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
struct prefix *ip)
{
memset(ip, 0, sizeof(struct prefix));
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
ip->family = AF_INET;
ip->prefixlen = IPV4_MAX_BITLEN;
memcpy(&(ip->u.prefix4),
&(evp->prefix.ip.ip),
IPV4_MAX_BYTELEN);
} else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
ip->family = AF_INET6;
ip->prefixlen = IPV6_MAX_BITLEN;
memcpy(&(ip->u.prefix6),
&(evp->prefix.ip.ip),
IPV6_MAX_BYTELEN);
}
}
static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
struct ethaddr *mac,
struct ipaddr *ip)
@ -185,6 +323,31 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
memcpy(&p->prefix.ip, ip, sizeof(*ip));
}
static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp,
struct prefix *ip_prefix)
{
struct ipaddr ip;
memset(&ip, 0, sizeof(struct ipaddr));
if (ip_prefix->family == AF_INET) {
ip.ipa_type = IPADDR_V4;
memcpy(&ip.ipaddr_v4, &ip_prefix->u.prefix4,
sizeof(struct in_addr));
} else {
ip.ipa_type = IPADDR_V6;
memcpy(&ip.ipaddr_v6, &ip_prefix->u.prefix6,
sizeof(struct in6_addr));
}
memset(evp, 0, sizeof(struct prefix_evpn));
evp->family = AF_EVPN;
evp->prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN;
evp->prefix.ip_prefix_length = ip_prefix->prefixlen;
evp->prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
evp->prefix.ip.ipa_type = ip.ipa_type;
memcpy(&evp->prefix.ip, &ip, sizeof(struct ipaddr));
}
static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
struct in_addr originator_ip)
{
@ -196,13 +359,41 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
p->prefix.ip.ipaddr_v4 = originator_ip;
}
static inline int advertise_type5_routes(struct bgp *bgp_vrf,
afi_t afi)
{
if (!bgp_vrf->l3vni)
return 0;
if (afi == AFI_IP &&
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
return 1;
if (afi == AFI_IP6 &&
CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
return 1;
return 0;
}
extern void evpn_rt_delete_auto(struct bgp*, vni_t, struct list*);
extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomadd);
extern void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel);
extern void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomadd);
extern void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel);
extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
struct bgpevpn *vpn);
extern void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf, int withdraw);
extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
int withdraw);
extern int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn);
extern int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf);
extern void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf);
extern void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp,
struct bgpevpn *vpn);
@ -211,8 +402,10 @@ extern void bgp_evpn_derive_auto_rt_import(struct bgp *bgp,
extern void bgp_evpn_derive_auto_rt_export(struct bgp *bgp,
struct bgpevpn *vpn);
extern void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn);
extern void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp);
extern struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni);
extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip);
struct in_addr originator_ip,
vrf_id_t tenant_vrf_id);
extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
#endif /* _BGP_EVPN_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@
#include "thread.h"
#include "log.h"
#include "stream.h"
#include "ringbuf.h"
#include "memory.h"
#include "plist.h"
#include "workqueue.h"
@ -155,7 +156,6 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
stream_fifo_clean(peer->ibuf);
stream_fifo_clean(peer->obuf);
stream_reset(peer->ibuf_work);
/*
* this should never happen, since bgp_process_packet() is the
@ -183,7 +183,9 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
stream_fifo_push(peer->ibuf,
stream_fifo_pop(from_peer->ibuf));
stream_copy(peer->ibuf_work, from_peer->ibuf_work);
ringbuf_wipe(peer->ibuf_work);
ringbuf_copy(peer->ibuf_work, from_peer->ibuf_work,
ringbuf_remain(from_peer->ibuf_work));
}
pthread_mutex_unlock(&from_peer->io_mtx);
pthread_mutex_unlock(&peer->io_mtx);
@ -264,14 +266,16 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
}
}
// Note: peer_xfer_stats() must be called with I/O turned OFF
if (from_peer)
peer_xfer_stats(peer, from_peer);
bgp_reads_on(peer);
bgp_writes_on(peer);
thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0,
&peer->t_process_packet);
if (from_peer)
peer_xfer_stats(peer, from_peer);
return (peer);
}
@ -1097,7 +1101,7 @@ int bgp_stop(struct peer *peer)
stream_fifo_clean(peer->obuf);
if (peer->ibuf_work)
stream_reset(peer->ibuf_work);
ringbuf_wipe(peer->ibuf_work);
if (peer->obuf_work)
stream_reset(peer->obuf_work);

View File

@ -29,6 +29,7 @@
#include "memory.h" // for MTYPE_TMP, XCALLOC, XFREE
#include "network.h" // for ERRNO_IO_RETRY
#include "stream.h" // for stream_get_endp, stream_getw_from, str...
#include "ringbuf.h" // for ringbuf_remain, ringbuf_peek, ringbuf_...
#include "thread.h" // for THREAD_OFF, THREAD_ARG, thread, thread...
#include "zassert.h" // for assert
@ -50,71 +51,12 @@ static bool validate_header(struct peer *);
#define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred
#define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error
/* Start and stop routines for I/O pthread + control variables
* ------------------------------------------------------------------------ */
_Atomic bool bgp_io_thread_run;
_Atomic bool bgp_io_thread_started;
void bgp_io_init()
{
bgp_io_thread_run = false;
bgp_io_thread_started = false;
}
/* Unused callback for thread_add_read() */
static int bgp_io_dummy(struct thread *thread) { return 0; }
void *bgp_io_start(void *arg)
{
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
fpt->master->owner = pthread_self();
// fd so we can sleep in poll()
int sleeper[2];
pipe(sleeper);
thread_add_read(fpt->master, &bgp_io_dummy, NULL, sleeper[0], NULL);
// we definitely don't want to handle signals
fpt->master->handle_signals = false;
struct thread task;
atomic_store_explicit(&bgp_io_thread_run, true, memory_order_seq_cst);
atomic_store_explicit(&bgp_io_thread_started, true,
memory_order_seq_cst);
while (bgp_io_thread_run) {
if (thread_fetch(fpt->master, &task)) {
thread_call(&task);
}
}
close(sleeper[1]);
close(sleeper[0]);
return NULL;
}
static int bgp_io_finish(struct thread *thread)
{
atomic_store_explicit(&bgp_io_thread_run, false, memory_order_seq_cst);
return 0;
}
int bgp_io_stop(void **result, struct frr_pthread *fpt)
{
thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL);
pthread_join(fpt->thread, result);
return 0;
}
/* Extern API -------------------------------------------------------------- */
/* Thread external API ----------------------------------------------------- */
void bgp_writes_on(struct peer *peer)
{
while (
!atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
;
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
assert(fpt->running);
assert(peer->status != Deleted);
assert(peer->obuf);
@ -124,8 +66,6 @@ void bgp_writes_on(struct peer *peer)
assert(!peer->t_connect_check_w);
assert(peer->fd);
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
thread_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
&peer->t_write);
SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
@ -133,11 +73,8 @@ void bgp_writes_on(struct peer *peer)
void bgp_writes_off(struct peer *peer)
{
while (
!atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
;
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
assert(fpt->running);
thread_cancel_async(fpt->master, &peer->t_write, NULL);
THREAD_OFF(peer->t_generate_updgrp_packets);
@ -147,9 +84,8 @@ void bgp_writes_off(struct peer *peer)
void bgp_reads_on(struct peer *peer)
{
while (
!atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
;
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
assert(fpt->running);
assert(peer->status != Deleted);
assert(peer->ibuf);
@ -160,8 +96,6 @@ void bgp_reads_on(struct peer *peer)
assert(!peer->t_connect_check_w);
assert(peer->fd);
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
@ -170,11 +104,8 @@ void bgp_reads_on(struct peer *peer)
void bgp_reads_off(struct peer *peer)
{
while (
!atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
;
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
assert(fpt->running);
thread_cancel_async(fpt->master, &peer->t_read, NULL);
THREAD_OFF(peer->t_process_packet);
@ -182,9 +113,9 @@ void bgp_reads_off(struct peer *peer)
UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
}
/* Internal functions ------------------------------------------------------- */
/* Thread internal functions ----------------------------------------------- */
/**
/*
* Called from I/O pthread when a file descriptor has become ready for writing.
*/
static int bgp_process_writes(struct thread *thread)
@ -207,11 +138,13 @@ static int bgp_process_writes(struct thread *thread)
}
pthread_mutex_unlock(&peer->io_mtx);
if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) { /* no problem */
/* no problem */
if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
}
/* problem */
if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
reschedule = false; /* problem */
reschedule = false;
fatal = true;
}
@ -226,7 +159,7 @@ static int bgp_process_writes(struct thread *thread)
return 0;
}
/**
/*
* Called from I/O pthread when a file descriptor has become ready for reading,
* or has hung up.
*
@ -273,14 +206,12 @@ static int bgp_process_reads(struct thread *thread)
/* static buffer for transferring packets */
static unsigned char pktbuf[BGP_MAX_PACKET_SIZE];
/* shorter alias to peer's input buffer */
struct stream *ibw = peer->ibuf_work;
/* offset of start of current packet */
size_t offset = stream_get_getp(ibw);
struct ringbuf *ibw = peer->ibuf_work;
/* packet size as given by header */
u_int16_t pktsize = 0;
uint16_t pktsize = 0;
/* check that we have enough data for a header */
if (STREAM_READABLE(ibw) < BGP_HEADER_SIZE)
if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
break;
/* validate header */
@ -292,16 +223,20 @@ static int bgp_process_reads(struct thread *thread)
}
/* header is valid; retrieve packet size */
pktsize = stream_getw_from(ibw, offset + BGP_MARKER_SIZE);
ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
pktsize = ntohs(pktsize);
/* if this fails we are seriously screwed */
assert(pktsize <= BGP_MAX_PACKET_SIZE);
/* If we have that much data, chuck it into its own
* stream and append to input queue for processing. */
if (STREAM_READABLE(ibw) >= pktsize) {
/*
* If we have that much data, chuck it into its own
* stream and append to input queue for processing.
*/
if (ringbuf_remain(ibw) >= pktsize) {
struct stream *pkt = stream_new(pktsize);
stream_get(pktbuf, ibw, pktsize);
assert(ringbuf_get(ibw, pktbuf, pktsize) == pktsize);
stream_put(pkt, pktbuf, pktsize);
pthread_mutex_lock(&peer->io_mtx);
@ -315,28 +250,12 @@ static int bgp_process_reads(struct thread *thread)
break;
}
/*
* After reading:
* 1. Move unread data to stream start to make room for more.
* 2. Reschedule and return when we have additional data.
*
* XXX: Heavy abuse of stream API. This needs a ring buffer.
*/
if (more && STREAM_WRITEABLE(peer->ibuf_work) < BGP_MAX_PACKET_SIZE) {
void *from = stream_pnt(peer->ibuf_work);
void *to = peer->ibuf_work->data;
size_t siz = STREAM_READABLE(peer->ibuf_work);
memmove(to, from, siz);
stream_set_getp(peer->ibuf_work, 0);
stream_set_endp(peer->ibuf_work, siz);
}
assert(STREAM_WRITEABLE(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE);
assert(ringbuf_space(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE);
/* handle invalid header */
if (fatal) {
/* wipe buffer just in case someone screwed up */
stream_reset(peer->ibuf_work);
ringbuf_wipe(peer->ibuf_work);
} else {
thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
@ -348,7 +267,7 @@ static int bgp_process_reads(struct thread *thread)
return 0;
}
/**
/*
* Flush peer output buffer.
*
* This function pops packets off of peer->obuf and writes them to peer->fd.
@ -367,15 +286,10 @@ static uint16_t bgp_write(struct peer *peer)
int num;
int update_last_write = 0;
unsigned int count = 0;
uint32_t oc;
uint32_t uo;
uint32_t uo = 0;
uint16_t status = 0;
uint32_t wpkt_quanta_old;
// save current # updates sent
oc = atomic_load_explicit(&peer->update_out, memory_order_relaxed);
// cache current write quanta
wpkt_quanta_old =
atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed);
@ -394,7 +308,7 @@ static uint16_t bgp_write(struct peer *peer)
}
goto done;
} else if (num != writenum) // incomplete write
} else if (num != writenum)
stream_forward_getp(s, num);
} while (num != writenum);
@ -411,6 +325,7 @@ static uint16_t bgp_write(struct peer *peer)
case BGP_MSG_UPDATE:
atomic_fetch_add_explicit(&peer->update_out, 1,
memory_order_relaxed);
uo++;
break;
case BGP_MSG_NOTIFY:
atomic_fetch_add_explicit(&peer->notify_out, 1,
@ -422,8 +337,10 @@ static uint16_t bgp_write(struct peer *peer)
if (peer->v_start >= (60 * 2))
peer->v_start = (60 * 2);
/* Handle Graceful Restart case where the state changes
* to Connect instead of Idle */
/*
* Handle Graceful Restart case where the state changes
* to Connect instead of Idle.
*/
BGP_EVENT_ADD(peer, BGP_Stop);
goto done;
@ -449,9 +366,12 @@ static uint16_t bgp_write(struct peer *peer)
}
done : {
/* Update last_update if UPDATEs were written. */
uo = atomic_load_explicit(&peer->update_out, memory_order_relaxed);
if (uo > oc)
/*
* Update last_update if UPDATEs were written.
* Note: that these are only updated at end,
* not per message (i.e., per loop)
*/
if (uo)
atomic_store_explicit(&peer->last_update, bgp_clock(),
memory_order_relaxed);
@ -464,7 +384,7 @@ done : {
return status;
}
/**
/*
* Reads a chunk of data from peer->fd into peer->ibuf_work.
*
* @return status flag (see top-of-file)
@ -474,14 +394,16 @@ static uint16_t bgp_read(struct peer *peer)
size_t readsize; // how many bytes we want to read
ssize_t nbytes; // how many bytes we actually read
uint16_t status = 0;
static uint8_t ibw[BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX];
readsize = STREAM_WRITEABLE(peer->ibuf_work);
readsize = MIN(ringbuf_space(peer->ibuf_work), sizeof(ibw));
nbytes = read(peer->fd, ibw, readsize);
nbytes = stream_read_try(peer->ibuf_work, peer->fd, readsize);
switch (nbytes) {
/* EAGAIN or EWOULDBLOCK; come back later */
if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
SET_FLAG(status, BGP_IO_TRANS_ERR);
/* Fatal error; tear down session */
case -1:
} else if (nbytes < 0) {
zlog_err("%s [Error] bgp_read_packet error: %s", peer->host,
safe_strerror(errno));
@ -495,10 +417,8 @@ static uint16_t bgp_read(struct peer *peer)
BGP_EVENT_ADD(peer, TCP_fatal_error);
SET_FLAG(status, BGP_IO_FATAL_ERR);
break;
/* Received EOF / TCP session closed */
case 0:
} else if (nbytes == 0) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [Event] BGP connection closed fd %d",
peer->host, peer->fd);
@ -513,14 +433,9 @@ static uint16_t bgp_read(struct peer *peer)
BGP_EVENT_ADD(peer, TCP_connection_closed);
SET_FLAG(status, BGP_IO_FATAL_ERR);
break;
/* EAGAIN or EWOULDBLOCK; come back later */
case -2:
SET_FLAG(status, BGP_IO_TRANS_ERR);
break;
default:
break;
} else {
assert(ringbuf_put(peer->ibuf_work, ibw, nbytes)
== (size_t)nbytes);
}
return status;
@ -529,27 +444,35 @@ static uint16_t bgp_read(struct peer *peer)
/*
* Called after we have read a BGP packet header. Validates marker, message
* type and packet length. If any of these aren't correct, sends a notify.
*
* Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input
* buffer.
*/
static bool validate_header(struct peer *peer)
{
uint16_t size;
uint8_t type;
struct stream *pkt = peer->ibuf_work;
size_t getp = stream_get_getp(pkt);
struct ringbuf *pkt = peer->ibuf_work;
static uint8_t marker[BGP_MARKER_SIZE] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static uint8_t m_correct[BGP_MARKER_SIZE] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t m_rx[BGP_MARKER_SIZE] = {0x00};
if (memcmp(marker, stream_pnt(pkt), BGP_MARKER_SIZE) != 0) {
if (ringbuf_peek(pkt, 0, m_rx, BGP_MARKER_SIZE) != BGP_MARKER_SIZE)
return false;
if (memcmp(m_correct, m_rx, BGP_MARKER_SIZE) != 0) {
bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_NOT_SYNC);
return false;
}
/* Get size and type in host byte order. */
size = stream_getw_from(pkt, getp + BGP_MARKER_SIZE);
type = stream_getc_from(pkt, getp + BGP_MARKER_SIZE + 2);
/* Get size and type in network byte order. */
ringbuf_peek(pkt, BGP_MARKER_SIZE, &size, sizeof(size));
ringbuf_peek(pkt, BGP_MARKER_SIZE + 2, &type, sizeof(type));
size = ntohs(size);
/* BGP type check. */
if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE

View File

@ -28,14 +28,6 @@
#include "bgpd/bgpd.h"
#include "frr_pthread.h"
/**
* Initializes data structures and flags for the write thread.
*
* This function should be called from the main thread before
* bgp_writes_start() is invoked.
*/
extern void bgp_io_init(void);
/**
* Start function for write thread.
*

View File

@ -36,14 +36,14 @@
#include "bgpd/bgp_keepalives.h"
/* clang-format on */
/**
/*
* Peer KeepAlive Timer.
* Associates a peer with the time of its last keepalive.
*/
struct pkat {
// the peer to send keepalives to
/* the peer to send keepalives to */
struct peer *peer;
// absolute time of last keepalive sent
/* absolute time of last keepalive sent */
struct timeval last;
};
@ -52,9 +52,6 @@ static pthread_mutex_t *peerhash_mtx;
static pthread_cond_t *peerhash_cond;
static struct hash *peerhash;
/* Thread control flag. */
bool bgp_keepalives_thread_run = false;
static struct pkat *pkat_new(struct peer *peer)
{
struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat));
@ -100,10 +97,10 @@ static void peer_process(struct hash_backet *hb, void *arg)
static struct timeval tolerance = {0, 100000};
// calculate elapsed time since last keepalive
/* calculate elapsed time since last keepalive */
monotime_since(&pkat->last, &elapsed);
// calculate difference between elapsed time and configured time
/* calculate difference between elapsed time and configured time */
ka.tv_sec = pkat->peer->v_keepalive;
timersub(&ka, &elapsed, &diff);
@ -118,10 +115,10 @@ static void peer_process(struct hash_backet *hb, void *arg)
bgp_keepalive_send(pkat->peer);
monotime(&pkat->last);
memset(&elapsed, 0x00, sizeof(struct timeval));
diff = ka; // time until next keepalive == peer keepalive time
diff = ka;
}
// if calculated next update for this peer < current delay, use it
/* if calculated next update for this peer < current delay, use it */
if (next_update->tv_sec <= 0 || timercmp(&diff, next_update, <))
*next_update = diff;
}
@ -139,29 +136,9 @@ static unsigned int peer_hash_key(void *arg)
return (uintptr_t)pkat->peer;
}
void bgp_keepalives_init()
{
peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
// initialize mutex
pthread_mutex_init(peerhash_mtx, NULL);
// use monotonic clock with condition variable
pthread_condattr_t attrs;
pthread_condattr_init(&attrs);
pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
pthread_cond_init(peerhash_cond, &attrs);
pthread_condattr_destroy(&attrs);
// initialize peer hashtable
peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
}
/* Cleanup handler / deinitializer. */
static void bgp_keepalives_finish(void *arg)
{
bgp_keepalives_thread_run = false;
if (peerhash) {
hash_clean(peerhash, pkat_del);
hash_free(peerhash);
@ -177,32 +154,50 @@ static void bgp_keepalives_finish(void *arg)
XFREE(MTYPE_TMP, peerhash_cond);
}
/**
/*
* Entry function for peer keepalive generation pthread.
*
* bgp_keepalives_init() must be called prior to this.
*/
void *bgp_keepalives_start(void *arg)
{
struct frr_pthread *fpt = arg;
fpt->master->owner = pthread_self();
struct timeval currtime = {0, 0};
struct timeval aftertime = {0, 0};
struct timeval next_update = {0, 0};
struct timespec next_update_ts = {0, 0};
peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
/* initialize mutex */
pthread_mutex_init(peerhash_mtx, NULL);
/* use monotonic clock with condition variable */
pthread_condattr_t attrs;
pthread_condattr_init(&attrs);
pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
pthread_cond_init(peerhash_cond, &attrs);
pthread_condattr_destroy(&attrs);
/* initialize peer hashtable */
peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
pthread_mutex_lock(peerhash_mtx);
// register cleanup handler
/* register cleanup handler */
pthread_cleanup_push(&bgp_keepalives_finish, NULL);
bgp_keepalives_thread_run = true;
/* notify anybody waiting on us that we are done starting up */
frr_pthread_notify_running(fpt);
while (bgp_keepalives_thread_run) {
while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
if (peerhash->count > 0)
pthread_cond_timedwait(peerhash_cond, peerhash_mtx,
&next_update_ts);
else
while (peerhash->count == 0
&& bgp_keepalives_thread_run)
&& atomic_load_explicit(&fpt->running,
memory_order_relaxed))
pthread_cond_wait(peerhash_cond, peerhash_mtx);
monotime(&currtime);
@ -219,7 +214,7 @@ void *bgp_keepalives_start(void *arg)
TIMEVAL_TO_TIMESPEC(&next_update, &next_update_ts);
}
// clean up
/* clean up */
pthread_cleanup_pop(1);
return NULL;
@ -229,6 +224,12 @@ void *bgp_keepalives_start(void *arg)
void bgp_keepalives_on(struct peer *peer)
{
if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
return;
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES);
assert(fpt->running);
/* placeholder bucket data to use for fast key lookups */
static struct pkat holder = {0};
@ -253,6 +254,12 @@ void bgp_keepalives_on(struct peer *peer)
void bgp_keepalives_off(struct peer *peer)
{
if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
return;
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES);
assert(fpt->running);
/* placeholder bucket data to use for fast key lookups */
static struct pkat holder = {0};
@ -283,10 +290,13 @@ void bgp_keepalives_wake()
pthread_mutex_unlock(peerhash_mtx);
}
int bgp_keepalives_stop(void **result, struct frr_pthread *fpt)
int bgp_keepalives_stop(struct frr_pthread *fpt, void **result)
{
bgp_keepalives_thread_run = false;
assert(fpt->running);
atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
bgp_keepalives_wake();
pthread_join(fpt->thread, result);
return 0;
}

View File

@ -88,6 +88,6 @@ extern void bgp_keepalives_wake(void);
/**
* Stops the thread and blocks until it terminates.
*/
int bgp_keepalives_stop(void **result, struct frr_pthread *fpt);
int bgp_keepalives_stop(struct frr_pthread *fpt, void **result);
#endif /* _FRR_BGP_KEEPALIVES_H */

View File

@ -221,6 +221,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
#endif
bgp_zebra_destroy();
bf_free(bm->rd_idspace);
list_delete_and_null(&bm->bgp);
memset(bm, 0, sizeof(*bm));
@ -231,7 +232,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
static int bgp_vrf_new(struct vrf *vrf)
{
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
return 0;
}
@ -239,7 +240,7 @@ static int bgp_vrf_new(struct vrf *vrf)
static int bgp_vrf_delete(struct vrf *vrf)
{
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
return 0;
}
@ -250,7 +251,7 @@ static int bgp_vrf_enable(struct vrf *vrf)
vrf_id_t old_vrf_id;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("VRF enable add %s id %d", vrf->name, vrf->vrf_id);
zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
bgp = bgp_lookup_by_name(vrf->name);
if (bgp) {

View File

@ -117,4 +117,5 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")

View File

@ -113,5 +113,6 @@ DECLARE_MTYPE(LCOMMUNITY_VAL)
DECLARE_MTYPE(BGP_EVPN)
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
DECLARE_MTYPE(BGP_EVPN_MACIP)
#endif /* _QUAGGA_BGP_MEMORY_H */

View File

@ -336,7 +336,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp) {
zlog_err(
"parse nexthop update: instance not found for vrf_id %d",
"parse nexthop update: instance not found for vrf_id %u",
vrf_id);
return;
}
@ -389,7 +389,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
char buf[PREFIX2STR_BUFFER];
prefix2str(&p, buf, sizeof(buf));
zlog_debug(
"%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
"%u: 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);
}
@ -572,12 +572,11 @@ static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p)
*/
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
{
struct stream *s;
struct prefix *p;
bool exact_match = false;
int ret;
/* Check socket. */
if (!zclient || zclient->sock < 0)
if (!zclient)
return;
/* Don't try to register if Zebra doesn't know of this instance. */
@ -585,32 +584,14 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
return;
p = &(bnc->node->p);
s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, command, bnc->bgp->vrf_id);
if ((command == ZEBRA_NEXTHOP_REGISTER ||
command == ZEBRA_IMPORT_ROUTE_REGISTER) &&
(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
stream_putc(s, 1);
else
stream_putc(s, 0);
exact_match = true;
stream_putw(s, PREFIX_FAMILY(p));
stream_putc(s, p->prefixlen);
switch (PREFIX_FAMILY(p)) {
case AF_INET:
stream_put_in_addr(s, &p->u.prefix4);
break;
case AF_INET6:
stream_put(s, &(p->u.prefix6), 16);
break;
default:
break;
}
stream_putw_at(s, 0, stream_get_endp(s));
ret = zclient_send_message(zclient);
ret = zclient_send_rnh(zclient, command, p,
exact_match, bnc->bgp->vrf_id);
/* TBD: handle the failure */
if (ret < 0)
zlog_warn("sendmsg_nexthop: zclient_send_message() failed");

View File

@ -545,19 +545,26 @@ void bgp_open_send(struct peer *peer)
bgp_writes_on(peer);
}
/* This is only for sending NOTIFICATION message to neighbor. */
/*
* Writes NOTIFICATION message directly to a peer socket without waiting for
* the I/O thread.
*
* There must be exactly one stream on the peer->obuf FIFO, and the data within
* this stream must match the format of a BGP NOTIFICATION message.
* Transmission is best-effort.
*
* @requires peer->io_mtx
* @param peer
* @return 0
*/
static int bgp_write_notify(struct peer *peer)
{
int ret, val;
u_char type;
struct stream *s;
pthread_mutex_lock(&peer->io_mtx);
{
/* There should be at least one packet. */
s = stream_fifo_pop(peer->obuf);
}
pthread_mutex_unlock(&peer->io_mtx);
/* There should be at least one packet. */
s = stream_fifo_pop(peer->obuf);
if (!s)
return 0;
@ -595,6 +602,7 @@ static int bgp_write_notify(struct peer *peer)
assert(type == BGP_MSG_NOTIFY);
/* Type should be notify. */
atomic_fetch_add_explicit(&peer->notify_out, 1, memory_order_relaxed);
peer->notify_out++;
/* Double start timer. */
@ -621,6 +629,14 @@ static int bgp_write_notify(struct peer *peer)
* This function attempts to write the packet from the thread it is called
* from, to ensure the packet gets out ASAP.
*
* This function may be called from multiple threads. Since the function
* modifies I/O buffer(s) in the peer, these are locked for the duration of the
* call to prevent tampering from other threads.
*
* Delivery of the NOTIFICATION is attempted once and is best-effort. After
* return, the peer structure *must* be reset; no assumptions about session
* state are valid.
*
* @param peer
* @param code BGP error code
* @param sub_code BGP error subcode
@ -633,6 +649,10 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
struct stream *s;
int length;
/* Lock I/O mutex to prevent other threads from pushing packets */
pthread_mutex_lock(&peer->io_mtx);
/* ============================================== */
/* Allocate new stream. */
s = stream_new(BGP_MAX_PACKET_SIZE);
@ -650,20 +670,8 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
/* Set BGP packet length. */
length = bgp_packet_set_size(s);
/*
* Turn off keepalive generation for peer. This is necessary because
* otherwise between the time we wipe the output buffer and the time we
* push the NOTIFY onto it, the KA generation thread could have pushed
* a KEEPALIVE in the middle.
*/
bgp_keepalives_off(peer);
/* wipe output buffer */
pthread_mutex_lock(&peer->io_mtx);
{
stream_fifo_clean(peer->obuf);
}
pthread_mutex_unlock(&peer->io_mtx);
stream_fifo_clean(peer->obuf);
/*
* If possible, store last packet for debugging purposes. This check is
@ -727,9 +735,12 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
/* Add packet to peer's output queue */
bgp_packet_add(peer, s);
stream_fifo_push(peer->obuf, s);
bgp_write_notify(peer);
/* ============================================== */
pthread_mutex_unlock(&peer->io_mtx);
}
/*
@ -1682,7 +1693,7 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
}
/* peer count update */
peer->notify_in++;
atomic_fetch_add_explicit(&peer->notify_in, 1, memory_order_relaxed);
peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED;
@ -2192,7 +2203,8 @@ int bgp_process_packet(struct thread *thread)
*/
switch (type) {
case BGP_MSG_OPEN:
peer->open_in++;
atomic_fetch_add_explicit(&peer->open_in, 1,
memory_order_relaxed);
mprc = bgp_open_receive(peer, size);
if (mprc == BGP_Stop)
zlog_err(
@ -2200,7 +2212,8 @@ int bgp_process_packet(struct thread *thread)
__FUNCTION__, peer->host);
break;
case BGP_MSG_UPDATE:
peer->update_in++;
atomic_fetch_add_explicit(&peer->update_in, 1,
memory_order_relaxed);
peer->readtime = monotime(NULL);
mprc = bgp_update_receive(peer, size);
if (mprc == BGP_Stop)
@ -2209,7 +2222,8 @@ int bgp_process_packet(struct thread *thread)
__FUNCTION__, peer->host);
break;
case BGP_MSG_NOTIFY:
peer->notify_in++;
atomic_fetch_add_explicit(&peer->notify_in, 1,
memory_order_relaxed);
mprc = bgp_notify_receive(peer, size);
if (mprc == BGP_Stop)
zlog_err(
@ -2218,7 +2232,8 @@ int bgp_process_packet(struct thread *thread)
break;
case BGP_MSG_KEEPALIVE:
peer->readtime = monotime(NULL);
peer->keepalive_in++;
atomic_fetch_add_explicit(&peer->keepalive_in, 1,
memory_order_relaxed);
mprc = bgp_keepalive_receive(peer, size);
if (mprc == BGP_Stop)
zlog_err(
@ -2227,7 +2242,8 @@ int bgp_process_packet(struct thread *thread)
break;
case BGP_MSG_ROUTE_REFRESH_NEW:
case BGP_MSG_ROUTE_REFRESH_OLD:
peer->refresh_in++;
atomic_fetch_add_explicit(&peer->refresh_in, 1,
memory_order_relaxed);
mprc = bgp_route_refresh_receive(peer, size);
if (mprc == BGP_Stop)
zlog_err(
@ -2235,7 +2251,8 @@ int bgp_process_packet(struct thread *thread)
__FUNCTION__, peer->host);
break;
case BGP_MSG_CAPABILITY:
peer->dynamic_cap_in++;
atomic_fetch_add_explicit(&peer->dynamic_cap_in, 1,
memory_order_relaxed);
mprc = bgp_capability_receive(peer, size);
if (mprc == BGP_Stop)
zlog_err(

View File

@ -166,8 +166,7 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
struct rd_as rd_as;
struct rd_ip rd_ip;
if (size < RD_ADDRSTRLEN)
return NULL;
assert(size >= RD_ADDRSTRLEN);
pnt = prd->val;
@ -197,5 +196,7 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
return buf;
}
#endif
return NULL;
snprintf(buf, size, "Unknown Type: %d", type);
return buf;
}

View File

@ -74,6 +74,9 @@
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_evpn_vty.h"
#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_route_clippy.c"
#endif
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
@ -2219,6 +2222,14 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
}
}
/* advertise/withdraw type-5 routes */
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
if (new_select)
bgp_evpn_advertise_type5_route(bgp, rn, afi, safi);
else if (old_select)
bgp_evpn_withdraw_type5_route(bgp, rn, afi, safi);
}
/* Clear any route change flags. */
bgp_zebra_clear_route_change_flags(rn);
@ -2708,7 +2719,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
/* AS path local-as loop check. */
if (peer->change_local_as) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
if (peer->allowas_in[afi][safi])
aspath_loop_count = peer->allowas_in[afi][safi];
else if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
aspath_loop_count = 1;
if (aspath_loop_check(attr->aspath, peer->change_local_as)
@ -4480,9 +4493,9 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
/* Configure static BGP network. When user don't run zebra, static
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,
u_int32_t label_index)
static int bgp_static_set(struct vty *vty, const char *negate,
const char *ip_str, afi_t afi, safi_t safi,
const char *rmap, int backdoor, u_int32_t label_index)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
@ -4504,113 +4517,110 @@ static int bgp_static_set(struct vty *vty, const char *ip_str, afi_t afi,
apply_mask(&p);
/* Set BGP static route configuration. */
rn = bgp_node_get(bgp->route[afi][safi], &p);
if (negate) {
if (rn->info) {
/* Configuration change. */
bgp_static = rn->info;
/* Set BGP static route configuration. */
rn = bgp_node_lookup(bgp->route[afi][safi], &p);
/* Label index cannot be changed. */
if (bgp_static->label_index != label_index) {
vty_out(vty, "%% Label index cannot be changed\n");
if (!rn) {
vty_out(vty,
"%% Can't find static route specified\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Check previous routes are installed into BGP. */
if (bgp_static->valid && bgp_static->backdoor != backdoor)
need_update = 1;
bgp_static = rn->info;
bgp_static->backdoor = backdoor;
if (rmap) {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
bgp_static->rmap.map = route_map_lookup_by_name(rmap);
} else {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
bgp_static->rmap.name = NULL;
bgp_static->rmap.map = NULL;
bgp_static->valid = 0;
if ((label_index != BGP_INVALID_LABEL_INDEX)
&& (label_index != bgp_static->label_index)) {
vty_out(vty,
"%% label-index doesn't match static route\n");
return CMD_WARNING_CONFIG_FAILED;
}
if ((rmap && bgp_static->rmap.name)
&& strcmp(rmap, bgp_static->rmap.name)) {
vty_out(vty,
"%% route-map name doesn't match static route\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Update BGP RIB. */
if (!bgp_static->backdoor)
bgp_static_withdraw(bgp, &p, afi, safi);
/* Clear configuration. */
bgp_static_free(bgp_static);
rn->info = NULL;
bgp_unlock_node(rn);
bgp_unlock_node(rn);
} else {
/* New configuration. */
bgp_static = bgp_static_new();
bgp_static->backdoor = backdoor;
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
bgp_static->label_index = label_index;
if (rmap) {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
bgp_static->rmap.map = route_map_lookup_by_name(rmap);
/* Set BGP static route configuration. */
rn = bgp_node_get(bgp->route[afi][safi], &p);
if (rn->info) {
/* Configuration change. */
bgp_static = rn->info;
/* Label index cannot be changed. */
if (bgp_static->label_index != label_index) {
vty_out(vty, "%% cannot change label-index\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Check previous routes are installed into BGP. */
if (bgp_static->valid &&
bgp_static->backdoor != backdoor)
need_update = 1;
bgp_static->backdoor = backdoor;
if (rmap) {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
bgp_static->rmap.map =
route_map_lookup_by_name(rmap);
} else {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
bgp_static->rmap.name = NULL;
bgp_static->rmap.map = NULL;
bgp_static->valid = 0;
}
bgp_unlock_node(rn);
} else {
/* New configuration. */
bgp_static = bgp_static_new();
bgp_static->backdoor = backdoor;
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
bgp_static->label_index = label_index;
if (rmap) {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
bgp_static->rmap.map =
route_map_lookup_by_name(rmap);
}
rn->info = bgp_static;
}
rn->info = bgp_static;
bgp_static->valid = 1;
if (need_update)
bgp_static_withdraw(bgp, &p, afi, safi);
if (!bgp_static->backdoor)
bgp_static_update(bgp, &p, bgp_static, afi, safi);
}
bgp_static->valid = 1;
if (need_update)
bgp_static_withdraw(bgp, &p, afi, safi);
if (!bgp_static->backdoor)
bgp_static_update(bgp, &p, bgp_static, afi, safi);
return CMD_SUCCESS;
}
/* Configure static BGP network. */
static int bgp_static_unset(struct vty *vty, const char *ip_str, afi_t afi,
safi_t safi)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
struct prefix p;
struct bgp_static *bgp_static;
struct bgp_node *rn;
/* Convert IP prefix string to struct prefix. */
ret = str2prefix(ip_str, &p);
if (!ret) {
vty_out(vty, "%% Malformed prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) {
vty_out(vty, "%% Malformed prefix (link-local address)\n");
return CMD_WARNING_CONFIG_FAILED;
}
apply_mask(&p);
rn = bgp_node_lookup(bgp->route[afi][safi], &p);
if (!rn) {
vty_out(vty,
"%% Can't find specified static route configuration.\n");
return CMD_WARNING_CONFIG_FAILED;
}
bgp_static = rn->info;
/* Update BGP RIB. */
if (!bgp_static->backdoor)
bgp_static_withdraw(bgp, &p, afi, safi);
/* Clear configuration. */
bgp_static_free(bgp_static);
rn->info = NULL;
bgp_unlock_node(rn);
bgp_unlock_node(rn);
return CMD_SUCCESS;
}
@ -5036,387 +5046,62 @@ DEFUN (no_bgp_table_map,
argv[idx_word]->arg);
}
DEFUN (bgp_network,
bgp_network_cmd,
"network A.B.C.D/M",
"Specify a network to announce via BGP\n"
"IPv4 prefix\n")
DEFPY(bgp_network,
bgp_network_cmd,
"[no] network \
<A.B.C.D/M$prefix|A.B.C.D$address [mask A.B.C.D$netmask]> \
[{route-map WORD$map_name|label-index (0-1048560)$label_index| \
backdoor$backdoor}]",
NO_STR
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
"Network number\n"
"Network mask\n"
"Network mask\n"
"Route-map to modify the attributes\n"
"Name of the route map\n"
"Label index to associate with the prefix\n"
"Label index value\n"
"Specify a BGP backdoor route\n")
{
int idx_ipv4_prefixlen = 1;
return bgp_static_set(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
bgp_node_safi(vty), NULL, 0,
BGP_INVALID_LABEL_INDEX);
}
char addr_prefix_str[BUFSIZ];
DEFUN (bgp_network_route_map,
bgp_network_route_map_cmd,
"network A.B.C.D/M route-map WORD",
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
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,
BGP_INVALID_LABEL_INDEX);
}
if (address_str) {
int ret;
DEFUN (bgp_network_backdoor,
bgp_network_backdoor_cmd,
"network A.B.C.D/M backdoor",
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
"Specify a BGP backdoor route\n")
{
int idx_ipv4_prefixlen = 1;
return bgp_static_set(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
SAFI_UNICAST, NULL, 1, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask,
bgp_network_mask_cmd,
"network A.B.C.D mask A.B.C.D",
"Specify a network to announce via BGP\n"
"Network number\n"
"Network mask\n"
"Network mask\n")
{
int idx_ipv4 = 1;
int idx_ipv4_2 = 3;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
ret = netmask_str2prefix_str(address_str, netmask_str,
addr_prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
}
return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), NULL,
0, BGP_INVALID_LABEL_INDEX);
return bgp_static_set(vty, no, address_str ? addr_prefix_str:prefix_str,
AFI_IP, bgp_node_safi(vty),
map_name, backdoor?1:0,
label_index ?
(uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_route_map,
bgp_network_mask_route_map_cmd,
"network A.B.C.D mask A.B.C.D route-map WORD",
"Specify a network to announce via BGP\n"
"Network number\n"
"Network mask\n"
"Network mask\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
DEFPY(ipv6_bgp_network,
ipv6_bgp_network_cmd,
"[no] network X:X::X:X/M$prefix \
[{route-map WORD$map_name|label-index (0-1048560)$label_index}]",
NO_STR
"Specify a network to announce via BGP\n"
"IPv6 prefix\n"
"Route-map to modify the attributes\n"
"Name of the route map\n"
"Label index to associate with the prefix\n"
"Label index value\n")
{
int idx_ipv4 = 1;
int idx_ipv4_2 = 3;
int idx_word = 5;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
return bgp_static_set(vty, no, prefix_str, AFI_IP6,
bgp_node_safi(vty), map_name, 0,
label_index ?
(uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_backdoor,
bgp_network_mask_backdoor_cmd,
"network A.B.C.D mask A.B.C.D backdoor",
"Specify a network to announce via BGP\n"
"Network number\n"
"Network mask\n"
"Network mask\n"
"Specify a BGP backdoor route\n")
{
int idx_ipv4 = 1;
int idx_ipv4_2 = 3;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_set(vty, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural,
bgp_network_mask_natural_cmd,
"network A.B.C.D",
"Specify a network to announce via BGP\n"
"Network number\n")
{
int idx_ipv4 = 1;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), NULL,
0, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural_route_map,
bgp_network_mask_natural_route_map_cmd,
"network A.B.C.D route-map WORD",
"Specify a network to announce via BGP\n"
"Network number\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
int idx_ipv4 = 1;
int idx_word = 3;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
}
DEFUN (bgp_network_mask_natural_backdoor,
bgp_network_mask_natural_backdoor_cmd,
"network A.B.C.D backdoor",
"Specify a network to announce via BGP\n"
"Network number\n"
"Specify a BGP backdoor route\n")
{
int idx_ipv4 = 1;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_set(vty, prefix_str, AFI_IP, SAFI_UNICAST, 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-1048560)",
"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;
label_index = strtoul(argv[3]->arg, NULL, 10);
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-1048560) 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;
label_index = strtoul(argv[3]->arg, NULL, 10);
return bgp_static_set(vty, argv[1]->arg, AFI_IP, bgp_node_safi(vty),
argv[5]->arg, 0, label_index);
}
DEFUN (no_bgp_network,
no_bgp_network_cmd,
"no network A.B.C.D/M [<backdoor|route-map WORD>]",
NO_STR
"Specify a network to announce via BGP\n"
"IPv4 prefix\n"
"Specify a BGP backdoor route\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
int idx_ipv4_prefixlen = 2;
return bgp_static_unset(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
bgp_node_safi(vty));
}
DEFUN (no_bgp_network_mask,
no_bgp_network_mask_cmd,
"no network A.B.C.D mask A.B.C.D [<backdoor|route-map WORD>]",
NO_STR
"Specify a network to announce via BGP\n"
"Network number\n"
"Network mask\n"
"Network mask\n"
"Specify a BGP backdoor route\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
int idx_ipv4 = 2;
int idx_ipv4_2 = 4;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_unset(vty, prefix_str, AFI_IP, bgp_node_safi(vty));
}
DEFUN (no_bgp_network_mask_natural,
no_bgp_network_mask_natural_cmd,
"no network A.B.C.D [<backdoor|route-map WORD>]",
NO_STR
"Specify a network to announce via BGP\n"
"Network number\n"
"Specify a BGP backdoor route\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
int idx_ipv4 = 2;
int ret;
char prefix_str[BUFSIZ];
ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
if (!ret) {
vty_out(vty, "%% Inconsistent address and mask\n");
return CMD_WARNING_CONFIG_FAILED;
}
return bgp_static_unset(vty, prefix_str, AFI_IP, bgp_node_safi(vty));
}
ALIAS(no_bgp_network, no_bgp_network_label_index_cmd,
"no network A.B.C.D/M label-index (0-1048560)", 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-1048560) 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",
"Specify a network to announce via BGP\n"
"IPv6 prefix\n")
{
int idx_ipv6_prefixlen = 1;
return bgp_static_set(vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
bgp_node_safi(vty), NULL, 0,
BGP_INVALID_LABEL_INDEX);
}
DEFUN (ipv6_bgp_network_route_map,
ipv6_bgp_network_route_map_cmd,
"network X:X::X:X/M route-map WORD",
"Specify a network to announce via BGP\n"
"IPv6 prefix\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
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_INVALID_LABEL_INDEX);
}
DEFUN (ipv6_bgp_network_label_index,
ipv6_bgp_network_label_index_cmd,
"network X:X::X:X/M label-index (0-1048560)",
"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;
label_index = strtoul(argv[3]->arg, NULL, 10);
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-1048560) 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;
label_index = strtoul(argv[3]->arg, NULL, 10);
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,
no_ipv6_bgp_network_cmd,
"no network X:X::X:X/M [route-map WORD]",
NO_STR
"Specify a network to announce via BGP\n"
"IPv6 prefix\n"
"Route-map to modify the attributes\n"
"Name of the route map\n")
{
int idx_ipv6_prefixlen = 2;
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-1048560)", 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-1048560) 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
@ -7388,7 +7073,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
vty_out(vty, " Imported from %s:%s\n",
prefix_rd2str(
(struct prefix_rd *)&prn->p,
buf1, RD_ADDRSTRLEN),
buf1, sizeof(buf1)),
buf2);
}
}
@ -7601,7 +7286,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
json_peer, "routerId",
inet_ntop(AF_INET,
&binfo->peer->remote_id, buf1,
BUFSIZ));
sizeof(buf1)));
if (binfo->peer->hostname)
json_object_string_add(
@ -7655,7 +7340,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
inet_ntop(
AF_INET,
&binfo->peer->remote_id,
buf1, BUFSIZ));
buf1, sizeof(buf1)));
}
}
@ -8174,7 +7859,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty,
"{\n \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64
",\n \"routerId\": \"%s\",\n \"routes\": { ",
bgp->vrf_id == VRF_UNKNOWN ? -1 : bgp->vrf_id,
bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id,
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ? "Default"
: bgp->name,
table->version, inet_ntoa(bgp->router_id));
@ -8394,8 +8079,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty, ",\"%s\": ", buf2);
vty_out(vty, "%s",
json_object_to_json_string_ext(json_paths, JSON_C_TO_STRING_PRETTY));
json_object_to_json_string(json_paths));
json_object_free(json_paths);
json_paths = NULL;
first = 0;
}
}
@ -8409,7 +8095,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
*total_cum = total_count;
}
if (use_json) {
json_object_free(json_paths);
if (json_paths)
json_object_free(json_paths);
if (is_last)
vty_out(vty, " } }\n");
else
@ -8440,6 +8127,9 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_node *rn, *next;
unsigned long output_cum = 0;
unsigned long total_cum = 0;
bool show_msg;
show_msg = (!use_json && type == bgp_show_type_normal);
for (rn = bgp_table_top(table); rn; rn = next) {
next = bgp_route_next(rn);
@ -8447,19 +8137,27 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
continue;
if (rn->info != NULL) {
struct prefix_rd prd;
char rd[BUFSIZ];
char rd[RD_ADDRSTRLEN];
memcpy(&prd, &(rn->p), sizeof(struct prefix_rd));
if (prefix_rd2str(&prd, rd, BUFSIZ) == NULL)
sprintf(rd,
"Unknown Type: %u",
decode_rd_type(prd.val));
prefix_rd2str(&prd, rd, sizeof(rd));
bgp_show_table(vty, bgp, safi, rn->info, type,
output_arg, use_json,
rd, next == NULL,
&output_cum, &total_cum);
if (next == NULL)
show_msg = false;
}
}
if (show_msg) {
if (output_cum == 0)
vty_out(vty, "No BGP prefixes displayed, %ld exist\n",
total_cum);
else
vty_out(vty,
"\nDisplayed %ld routes and %ld total paths\n",
output_cum, total_cum);
}
if (use_json)
vty_out(vty, " } }");
return CMD_SUCCESS;
@ -8539,7 +8237,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
struct prefix *p;
struct peer *peer;
struct listnode *node, *nnode;
char buf1[INET6_ADDRSTRLEN];
char buf1[RD_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
#if defined(HAVE_CUMULUS)
char buf3[EVPN_ROUTE_STRLEN];
@ -8573,7 +8271,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
#if defined(HAVE_CUMULUS)
if (safi == SAFI_EVPN)
vty_out(vty, "BGP routing table entry for %s%s%s\n",
prd ? prefix_rd2str(prd, buf1, RD_ADDRSTRLEN)
prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
: "",
prd ? ":" : "",
bgp_evpn_route2str((struct prefix_evpn *)p,
@ -8582,7 +8280,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
? prefix_rd2str(prd, buf1,
RD_ADDRSTRLEN)
sizeof(buf1))
: ""),
safi == SAFI_MPLS_VPN ? ":" : "",
inet_ntop(p->family, &p->u.prefix, buf2,
@ -8597,8 +8295,8 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|| safi == SAFI_EVPN)
? prefix_rd2str(prd, buf1, RD_ADDRSTRLEN)
: ""),
? prefix_rd2str(prd, buf1, sizeof(buf1))
: ""),
((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":"
: "",
buf2, p->prefixlen);
@ -10569,12 +10267,17 @@ DEFUN (show_bgp_afi_vpn_rd_route,
afi_t afi = AFI_MAX;
int idx = 0;
(void)argv_find_and_parse_afi(argv, argc, &idx, &afi);
if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
vty_out(vty, "%% Malformed Address Family\n");
return CMD_WARNING;
}
ret = str2prefix_rd(argv[5]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd,
0, BGP_PATH_ALL, use_json(argc, argv));
}
@ -11139,7 +10842,7 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
prd = (struct prefix_rd *)&prn->p;
/* "network" configuration display. */
prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN);
prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
label = decode_label(&bgp_static->label);
vty_out(vty, " network %s/%d rd %s",
@ -11152,10 +10855,10 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
if (bgp_static->rmap.name)
vty_out(vty, " route-map %s",
bgp_static->rmap.name);
else {
if (bgp_static->backdoor)
vty_out(vty, " backdoor");
}
if (bgp_static->backdoor)
vty_out(vty, " backdoor");
vty_out(vty, "\n");
}
}
@ -11196,7 +10899,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
prd = (struct prefix_rd *)&prn->p;
/* "network" configuration display. */
prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN);
prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
if (p->u.prefix_evpn.route_type == 5) {
char local_buf[PREFIX_STRLEN];
uint8_t family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)
@ -11215,7 +10918,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
&bgp_static->gatewayIp.u.prefix, buf2,
sizeof(buf2));
vty_out(vty,
" network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s\n",
" network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
buf, rdbuf, p->u.prefix_evpn.eth_tag,
decode_label(&bgp_static->label), esi, buf2,
macrouter);
@ -11288,10 +10991,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp_static->rmap.name)
vty_out(vty, " route-map %s", bgp_static->rmap.name);
else {
if (bgp_static->backdoor)
vty_out(vty, " backdoor");
}
if (bgp_static->backdoor)
vty_out(vty, " backdoor");
vty_out(vty, "\n");
}
@ -11374,18 +11076,7 @@ void bgp_route_init(void)
/* IPv4 BGP commands. */
install_element(BGP_NODE, &bgp_table_map_cmd);
install_element(BGP_NODE, &bgp_network_cmd);
install_element(BGP_NODE, &bgp_network_mask_cmd);
install_element(BGP_NODE, &bgp_network_mask_natural_cmd);
install_element(BGP_NODE, &bgp_network_route_map_cmd);
install_element(BGP_NODE, &bgp_network_mask_route_map_cmd);
install_element(BGP_NODE, &bgp_network_mask_natural_route_map_cmd);
install_element(BGP_NODE, &bgp_network_backdoor_cmd);
install_element(BGP_NODE, &bgp_network_mask_backdoor_cmd);
install_element(BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
install_element(BGP_NODE, &no_bgp_table_map_cmd);
install_element(BGP_NODE, &no_bgp_network_cmd);
install_element(BGP_NODE, &no_bgp_network_mask_cmd);
install_element(BGP_NODE, &no_bgp_network_mask_natural_cmd);
install_element(BGP_NODE, &aggregate_address_cmd);
install_element(BGP_NODE, &aggregate_address_mask_cmd);
@ -11395,20 +11086,7 @@ void bgp_route_init(void)
/* IPv4 unicast configuration. */
install_element(BGP_IPV4_NODE, &bgp_table_map_cmd);
install_element(BGP_IPV4_NODE, &bgp_network_cmd);
install_element(BGP_IPV4_NODE, &bgp_network_mask_cmd);
install_element(BGP_IPV4_NODE, &bgp_network_mask_natural_cmd);
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_IPV4_NODE, &bgp_network_label_index_cmd);
install_element(BGP_IPV4_NODE, &bgp_network_label_index_route_map_cmd);
install_element(BGP_IPV4_NODE, &no_bgp_network_label_index_cmd);
install_element(BGP_IPV4_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);
install_element(BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd);
install_element(BGP_IPV4_NODE, &aggregate_address_cmd);
install_element(BGP_IPV4_NODE, &aggregate_address_mask_cmd);
@ -11418,16 +11096,7 @@ void bgp_route_init(void)
/* IPv4 multicast configuration. */
install_element(BGP_IPV4M_NODE, &bgp_table_map_cmd);
install_element(BGP_IPV4M_NODE, &bgp_network_cmd);
install_element(BGP_IPV4M_NODE, &bgp_network_mask_cmd);
install_element(BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd);
install_element(BGP_IPV4M_NODE, &bgp_network_route_map_cmd);
install_element(BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd);
install_element(BGP_IPV4M_NODE,
&bgp_network_mask_natural_route_map_cmd);
install_element(BGP_IPV4M_NODE, &no_bgp_table_map_cmd);
install_element(BGP_IPV4M_NODE, &no_bgp_network_cmd);
install_element(BGP_IPV4M_NODE, &no_bgp_network_mask_cmd);
install_element(BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd);
install_element(BGP_IPV4M_NODE, &aggregate_address_cmd);
install_element(BGP_IPV4M_NODE, &aggregate_address_mask_cmd);
install_element(BGP_IPV4M_NODE, &no_aggregate_address_cmd);
@ -11470,21 +11139,12 @@ void bgp_route_init(void)
/* New config IPv6 BGP commands. */
install_element(BGP_IPV6_NODE, &bgp_table_map_cmd);
install_element(BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
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);
install_element(BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
install_element(BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
install_element(BGP_NODE, &bgp_distance_cmd);
install_element(BGP_NODE, &no_bgp_distance_cmd);

View File

@ -73,9 +73,12 @@ struct bgp_info_extra {
/* Nexthop reachability check. */
u_int32_t igpmetric;
/* MPLS label. */
/* MPLS label - L2VNI */
mpls_label_t label;
/* MPLS label - L3-VNI */
mpls_label_t label2;
#if ENABLE_BGP_VNC
union {

View File

@ -2082,7 +2082,10 @@ static void *route_set_aggregator_as_compile(const char *arg)
aggregator =
XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct aggregator));
sscanf(arg, "%s %s", as, address);
if (sscanf(arg, "%s %s", as, address) != 2) {
XFREE(MTYPE_ROUTE_MAP_COMPILED, aggregator);
return NULL;
}
aggregator->as = strtoul(as, NULL, 10);
ret = inet_aton(address, &aggregator->address);

View File

@ -512,6 +512,7 @@ static u_char *bgpPeerTable(struct variable *v, oid name[], size_t *length,
{
static struct in_addr addr;
struct peer *peer;
uint32_t ui, uo;
if (smux_header_table(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
@ -571,21 +572,20 @@ static u_char *bgpPeerTable(struct variable *v, oid name[], size_t *length,
return SNMP_INTEGER(peer->as);
break;
case BGPPEERINUPDATES:
return SNMP_INTEGER(peer->update_in);
ui = atomic_load_explicit(&peer->update_in,
memory_order_relaxed);
return SNMP_INTEGER(ui);
break;
case BGPPEEROUTUPDATES:
return SNMP_INTEGER(peer->update_out);
uo = atomic_load_explicit(&peer->update_out,
memory_order_relaxed);
return SNMP_INTEGER(uo);
break;
case BGPPEERINTOTALMESSAGES:
return SNMP_INTEGER(peer->open_in + peer->update_in
+ peer->keepalive_in + peer->notify_in
+ peer->refresh_in + peer->dynamic_cap_in);
return SNMP_INTEGER(PEER_TOTAL_RX(peer));
break;
case BGPPEEROUTTOTALMESSAGES:
return SNMP_INTEGER(peer->open_out + peer->update_out
+ peer->keepalive_out + peer->notify_out
+ peer->refresh_out
+ peer->dynamic_cap_out);
return SNMP_INTEGER(PEER_TOTAL_TX(peer));
break;
case BGPPEERLASTERROR: {
static u_char lasterror[2];

View File

@ -58,6 +58,7 @@
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_bfd.h"
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_evpn.h"
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
@ -873,6 +874,8 @@ DEFUN_NOSH (router_bgp,
*/
}
/* unset the auto created flag as the user config is now present */
UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
VTY_PUSH_CONTEXT(BGP_NODE, bgp);
return CMD_SUCCESS;
@ -909,6 +912,12 @@ DEFUN (no_router_bgp,
"%% Multiple BGP processes are configured\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (bgp->l3vni) {
vty_out(vty, "%% Please unconfigure l3vni %u",
bgp->l3vni);
return CMD_WARNING_CONFIG_FAILED;
}
} else {
as = strtoul(argv[idx_asn]->arg, NULL, 10);
@ -921,6 +930,12 @@ DEFUN (no_router_bgp,
vty_out(vty, "%% Can't find BGP instance\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (bgp->l3vni) {
vty_out(vty, "%% Please unconfigure l3vni %u",
bgp->l3vni);
return CMD_WARNING_CONFIG_FAILED;
}
}
bgp_delete(bgp);
@ -1423,7 +1438,7 @@ DEFUN (no_bgp_rpkt_quanta,
void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
{
if (bgp->coalesce_time != BGP_DEFAULT_SUBGROUP_COALESCE_TIME)
if (!bgp->heuristic_coalesce)
vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time);
}
@ -1438,6 +1453,7 @@ DEFUN (bgp_coalesce_time,
int idx = 0;
argv_find(argv, argc, "(0-4294967295)", &idx);
bgp->heuristic_coalesce = false;
bgp->coalesce_time = strtoul(argv[idx]->arg, NULL, 10);
return CMD_SUCCESS;
}
@ -1451,6 +1467,7 @@ DEFUN (no_bgp_coalesce_time,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp->heuristic_coalesce = true;
bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
return CMD_SUCCESS;
}
@ -2675,6 +2692,19 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
return bgp_vty_return(vty, ret);
}
DEFUN (bgp_default_shutdown,
bgp_default_shutdown_cmd,
"[no] bgp default shutdown",
NO_STR
BGP_STR
"Configure BGP defaults\n"
"Do not automatically activate peers upon configuration\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp->autoshutdown = !strmatch(argv[0]->text, "no");
return CMD_SUCCESS;
}
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>",
@ -3221,7 +3251,6 @@ DEFUN (no_neighbor_password,
return bgp_vty_return(vty, ret);
}
DEFUN (neighbor_activate,
neighbor_activate_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> activate",
@ -6448,6 +6477,7 @@ DEFUN (show_bgp_vrfs,
"Show BGP VRFs\n"
JSON_STR)
{
char buf[ETHER_ADDR_STRLEN];
struct list *inst = bm->bgp;
struct listnode *node;
struct bgp *bgp;
@ -6455,8 +6485,6 @@ DEFUN (show_bgp_vrfs,
json_object *json = NULL;
json_object *json_vrfs = NULL;
int count = 0;
static char header[] =
"Type Id RouterId #PeersCfg #PeersEstb Name";
if (!bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
vty_out(vty, "BGP Multiple Instance is not enabled\n");
@ -6474,7 +6502,6 @@ DEFUN (show_bgp_vrfs,
struct listnode *node, *nnode;
int peers_cfg, peers_estb;
json_object *json_vrf = NULL;
int vrf_id_ui;
/* Skip Views. */
if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
@ -6482,7 +6509,10 @@ DEFUN (show_bgp_vrfs,
count++;
if (!uj && count == 1)
vty_out(vty, "%s\n", header);
vty_out(vty,
"%4s %-5s %-16s %9s %10s %-37s %-10s %-15s\n",
"Type", "Id", "routerId", "#PeersVfg",
"#PeersEstb", "Name", "L3-VNI", "Rmac");
peers_cfg = peers_estb = 0;
if (uj)
@ -6505,8 +6535,10 @@ DEFUN (show_bgp_vrfs,
type = "VRF";
}
vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
if (uj) {
int64_t vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 :
(int64_t)bgp->vrf_id;
json_object_string_add(json_vrf, "type", type);
json_object_int_add(json_vrf, "vrfId", vrf_id_ui);
json_object_string_add(json_vrf, "routerId",
@ -6516,11 +6548,19 @@ DEFUN (show_bgp_vrfs,
json_object_int_add(json_vrf, "numEstablishedPeers",
peers_estb);
json_object_int_add(json_vrf, "l3vni", bgp->l3vni);
json_object_string_add(json_vrf, "rmac",
prefix_mac2str(&bgp->rmac, buf,
sizeof(buf)));
json_object_object_add(json_vrfs, name, json_vrf);
} else
vty_out(vty, "%4s %-5d %-16s %9u %10u %s\n", type,
vrf_id_ui, inet_ntoa(bgp->router_id), peers_cfg,
peers_estb, name);
vty_out(vty,
"%4s %-5d %-16s %9u %10u %-37s %-10u %-15s\n",
type, bgp->vrf_id == VRF_UNKNOWN ?
-1 : (int)bgp->vrf_id,
inet_ntoa(bgp->router_id),
peers_cfg, peers_estb, name, bgp->l3vni,
prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
}
if (uj) {
@ -6838,10 +6878,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (!count) {
unsigned long ents;
char memstrbuf[MTYPE_MEMSTR_LEN];
int vrf_id_ui;
int64_t vrf_id_ui;
vrf_id_ui =
(bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
(bgp->vrf_id == VRF_UNKNOWN) ? -1 :
(int64_t)bgp->vrf_id;
/* Usage summary and header */
if (use_json) {
@ -6860,7 +6901,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
vty_out(vty,
"BGP router identifier %s, local AS number %u vrf-id %d",
inet_ntoa(bgp->router_id), bgp->as,
vrf_id_ui);
bgp->vrf_id == VRF_UNKNOWN ? -1 :
(int)bgp->vrf_id);
vty_out(vty, "\n");
}
@ -7051,17 +7093,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_int_add(json_peer, "remoteAs", peer->as);
json_object_int_add(json_peer, "version", 4);
json_object_int_add(json_peer, "msgRcvd",
peer->open_in + peer->update_in
+ peer->keepalive_in
+ peer->notify_in
+ peer->refresh_in
+ peer->dynamic_cap_in);
PEER_TOTAL_RX(peer));
json_object_int_add(json_peer, "msgSent",
peer->open_out + peer->update_out
+ peer->keepalive_out
+ peer->notify_out
+ peer->refresh_out
+ peer->dynamic_cap_out);
PEER_TOTAL_TX(peer));
json_object_int_add(json_peer, "tableVersion",
peer->version[afi][safi]);
@ -7118,48 +7152,18 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
" ");
vty_out(vty, "4 %10u %7u %7u %8" PRIu64 " %4d %4zd %8s",
peer->as,
atomic_load_explicit(&peer->open_in,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->update_in,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->keepalive_in,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->notify_in,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->refresh_in,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->dynamic_cap_in,
memory_order_relaxed),
atomic_load_explicit(&peer->open_out,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->update_out,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->keepalive_out,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->notify_out,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->refresh_out,
memory_order_relaxed)
+ atomic_load_explicit(
&peer->dynamic_cap_out,
memory_order_relaxed),
peer->version[afi][safi], 0, peer->obuf->count,
peer->as, PEER_TOTAL_RX(peer),
PEER_TOTAL_TX(peer), peer->version[afi][safi],
0, peer->obuf->count,
peer_uptime(peer->uptime, timebuf,
BGP_UPTIME_LEN, 0, NULL));
if (peer->status == Established)
vty_out(vty, " %12ld",
peer->pcount[afi][pfx_rcd_safi]);
if (peer->afc_recv[afi][pfx_rcd_safi])
vty_out(vty, " %12ld",
peer->pcount[afi][pfx_rcd_safi]);
else
vty_out(vty, " NoNeg");
else {
if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
vty_out(vty, " Idle (Admin)");
@ -7721,7 +7725,7 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
}
if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
if (p->bgp->advertise_all_vni)
if (is_evpn_enabled())
json_object_boolean_true_add(
json_addr, "advertiseAllVnis");
}
@ -7993,7 +7997,7 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
/* advertise-vni-all */
if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
if (p->bgp->advertise_all_vni)
if (is_evpn_enabled())
vty_out(vty, " advertise-all-vni\n");
}
@ -8286,17 +8290,29 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
if (p->status == Established) {
time_t uptime;
struct tm *tm;
uptime = bgp_clock();
uptime -= p->uptime;
tm = gmtime(&uptime);
epoch_tbuf = time(NULL) - uptime;
#if CONFDATE > 20200101
CPP_NOTICE("bgpTimerUp should be deprecated and can be removed now");
#endif
/*
* bgpTimerUp was miliseconds that was accurate
* up to 1 day, then the value returned
* became garbage. So in order to provide
* some level of backwards compatability,
* we still provde the data, but now
* we are returning the correct value
* and also adding a new bgpTimerUpMsec
* which will allow us to deprecate
* this eventually
*/
json_object_int_add(json_neigh, "bgpTimerUp",
(tm->tm_sec * 1000)
+ (tm->tm_min * 60000)
+ (tm->tm_hour * 3600000));
uptime * 1000);
json_object_int_add(json_neigh, "bgpTimerUpMsec",
uptime * 1000);
json_object_string_add(json_neigh, "bgpTimerUpString",
peer_uptime(p->uptime, timebuf,
BGP_UPTIME_LEN, 0,
@ -9327,34 +9343,44 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
json_object_int_add(json_stat, "depthInq", 0);
json_object_int_add(json_stat, "depthOutq",
(unsigned long)p->obuf->count);
json_object_int_add(json_stat, "opensSent", p->open_out);
json_object_int_add(json_stat, "opensRecv", p->open_in);
json_object_int_add(json_stat, "opensSent",
atomic_load_explicit(&p->open_out,
memory_order_relaxed));
json_object_int_add(json_stat, "opensRecv",
atomic_load_explicit(&p->open_in,
memory_order_relaxed));
json_object_int_add(json_stat, "notificationsSent",
p->notify_out);
atomic_load_explicit(&p->notify_out,
memory_order_relaxed));
json_object_int_add(json_stat, "notificationsRecv",
p->notify_in);
json_object_int_add(json_stat, "updatesSent", p->update_out);
json_object_int_add(json_stat, "updatesRecv", p->update_in);
atomic_load_explicit(&p->notify_in,
memory_order_relaxed));
json_object_int_add(json_stat, "updatesSent",
atomic_load_explicit(&p->update_out,
memory_order_relaxed));
json_object_int_add(json_stat, "updatesRecv",
atomic_load_explicit(&p->update_in,
memory_order_relaxed));
json_object_int_add(json_stat, "keepalivesSent",
p->keepalive_out);
atomic_load_explicit(&p->keepalive_out,
memory_order_relaxed));
json_object_int_add(json_stat, "keepalivesRecv",
p->keepalive_in);
atomic_load_explicit(&p->keepalive_in,
memory_order_relaxed));
json_object_int_add(json_stat, "routeRefreshSent",
p->refresh_out);
atomic_load_explicit(&p->refresh_out,
memory_order_relaxed));
json_object_int_add(json_stat, "routeRefreshRecv",
p->refresh_in);
atomic_load_explicit(&p->refresh_in,
memory_order_relaxed));
json_object_int_add(json_stat, "capabilitySent",
p->dynamic_cap_out);
atomic_load_explicit(&p->dynamic_cap_out,
memory_order_relaxed));
json_object_int_add(json_stat, "capabilityRecv",
p->dynamic_cap_in);
json_object_int_add(json_stat, "totalSent",
p->open_out + p->notify_out + p->update_out
+ p->keepalive_out + p->refresh_out
+ p->dynamic_cap_out);
json_object_int_add(json_stat, "totalRecv",
p->open_in + p->notify_in + p->update_in
+ p->keepalive_in + p->refresh_in
+ p->dynamic_cap_in);
atomic_load_explicit(&p->dynamic_cap_in,
memory_order_relaxed));
json_object_int_add(json_stat, "totalSent", PEER_TOTAL_TX(p));
json_object_int_add(json_stat, "totalRecv", PEER_TOTAL_RX(p));
json_object_object_add(json_neigh, "messageStats", json_stat);
} else {
/* Packet counts. */
@ -9363,25 +9389,38 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
vty_out(vty, " Outq depth is %lu\n",
(unsigned long)p->obuf->count);
vty_out(vty, " Sent Rcvd\n");
vty_out(vty, " Opens: %10d %10d\n", p->open_out,
p->open_in);
vty_out(vty, " Notifications: %10d %10d\n", p->notify_out,
p->notify_in);
vty_out(vty, " Updates: %10d %10d\n", p->update_out,
p->update_in);
vty_out(vty, " Keepalives: %10d %10d\n", p->keepalive_out,
p->keepalive_in);
vty_out(vty, " Route Refresh: %10d %10d\n", p->refresh_out,
p->refresh_in);
vty_out(vty, " Opens: %10d %10d\n",
atomic_load_explicit(&p->open_out,
memory_order_relaxed),
atomic_load_explicit(&p->open_in,
memory_order_relaxed));
vty_out(vty, " Notifications: %10d %10d\n",
atomic_load_explicit(&p->notify_out,
memory_order_relaxed),
atomic_load_explicit(&p->notify_in,
memory_order_relaxed));
vty_out(vty, " Updates: %10d %10d\n",
atomic_load_explicit(&p->update_out,
memory_order_relaxed),
atomic_load_explicit(&p->update_in,
memory_order_relaxed));
vty_out(vty, " Keepalives: %10d %10d\n",
atomic_load_explicit(&p->keepalive_out,
memory_order_relaxed),
atomic_load_explicit(&p->keepalive_in,
memory_order_relaxed));
vty_out(vty, " Route Refresh: %10d %10d\n",
atomic_load_explicit(&p->refresh_out,
memory_order_relaxed),
atomic_load_explicit(&p->refresh_in,
memory_order_relaxed));
vty_out(vty, " Capability: %10d %10d\n",
p->dynamic_cap_out, p->dynamic_cap_in);
vty_out(vty, " Total: %10d %10d\n",
p->open_out + p->notify_out + p->update_out
+ p->keepalive_out + p->refresh_out
+ p->dynamic_cap_out,
p->open_in + p->notify_in + p->update_in
+ p->keepalive_in + p->refresh_in
+ p->dynamic_cap_in);
atomic_load_explicit(&p->dynamic_cap_out,
memory_order_relaxed),
atomic_load_explicit(&p->dynamic_cap_in,
memory_order_relaxed));
vty_out(vty, " Total: %10d %10d\n", PEER_TOTAL_TX(p),
PEER_TOTAL_RX(p));
}
if (use_json) {
@ -9831,7 +9870,6 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
}
if (use_json) {
bgp_show_bestpath_json(bgp, json);
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
@ -9843,12 +9881,15 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
}
static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
enum show_type type,
const char *ip_str,
u_char use_json)
{
struct listnode *node, *nnode;
struct bgp *bgp;
union sockunion su;
json_object *json = NULL;
int is_first = 1;
int ret, is_first = 1;
if (use_json)
vty_out(vty, "{\n");
@ -9865,8 +9906,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
json_object_int_add(json, "vrfId",
(bgp->vrf_id == VRF_UNKNOWN)
? -1
: bgp->vrf_id);
? -1 : (int64_t) bgp->vrf_id);
json_object_string_add(
json, "vrfName",
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
@ -9888,8 +9928,19 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
? "Default"
: bgp->name);
}
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, use_json,
json);
if (type == show_peer) {
ret = str2sockunion(ip_str, &su);
if (ret < 0)
bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
use_json, json);
else
bgp_show_neighbor(vty, bgp, type, &su, NULL,
use_json, json);
} else {
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
use_json, json);
}
}
if (use_json)
@ -9907,7 +9958,8 @@ static int bgp_show_neighbor_vty(struct vty *vty, const char *name,
if (name) {
if (strmatch(name, "all")) {
bgp_show_all_instances_neighbors_vty(vty, use_json);
bgp_show_all_instances_neighbors_vty(vty, type, ip_str,
use_json);
return CMD_SUCCESS;
} else {
bgp = bgp_lookup_by_name(name);
@ -11556,6 +11608,9 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_listen_range_cmd);
install_element(BGP_NODE, &no_bgp_listen_range_cmd);
/* "neighbors auto-shutdown" command */
install_element(BGP_NODE, &bgp_default_shutdown_cmd);
/* "neighbor remote-as" commands. */
install_element(BGP_NODE, &neighbor_remote_as_cmd);
install_element(BGP_NODE, &neighbor_interface_config_cmd);

View File

@ -999,7 +999,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
/* Make Zebra API structure. */
memset(&api, 0, sizeof(api));
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
api.vrf_id = bgp->vrf_id;
api.nh_vrf_id = bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
api.safi = safi;
api.prefix = *p;
@ -1015,6 +1017,13 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (info->sub_type == BGP_ROUTE_AGGREGATE)
zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
/* If it is an EVPN route mark as such.
* Currently presence of rmac in attr denotes
* this is an EVPN type-2 route
*/
if (!is_zero_mac(&(info->attr->rmac)))
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|| info->sub_type == BGP_ROUTE_AGGREGATE) {
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
@ -1072,7 +1081,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
api_nh = &api.nexthops[valid_nh_count];
api_nh->gate.ipv4 = *nexthop;
api_nh->type = NEXTHOP_TYPE_IPV4;
/* EVPN type-2 routes are
programmed as onlink on l3-vni SVI
*/
if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
else
api_nh->type = NEXTHOP_TYPE_IPV4;
} else {
ifindex_t ifindex;
struct in6_addr *nexthop;
@ -1126,8 +1142,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
}
if (mpinfo->extra
&& bgp_is_valid_label(&mpinfo->extra->label)) {
if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label)
&& !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
has_valid_label = 1;
label = label_pton(&mpinfo->extra->label);
@ -1137,7 +1153,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
valid_nh_count++;
}
if (has_valid_label)
/* if this is a evpn route we don't have to include the label */
if (has_valid_label &&
!(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)))
SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
if (info->sub_type != BGP_ROUTE_AGGREGATE)
@ -1179,7 +1197,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
sizeof(nh_buf));
label_buf[0] = '\0';
if (has_valid_label)
if (has_valid_label &&
!CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))
sprintf(label_buf, "label %u",
api_nh->labels[0]);
zlog_debug(" nhop [%d]: %s %s", i + 1, nh_buf,
@ -1233,11 +1252,20 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
return;
memset(&api, 0, sizeof(api));
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
api.vrf_id = peer->bgp->vrf_id;
api.nh_vrf_id = peer->bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
api.safi = safi;
api.prefix = *p;
/* If it is an EVPN route mark as such.
* Currently presence of rmac in attr denotes
* this is an EVPN type-2 route
*/
if (!is_zero_mac(&(info->attr->rmac)))
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
if (peer->sort == BGP_PEER_IBGP) {
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
@ -1516,8 +1544,9 @@ void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (vrf_bitmap_check(zclient->redist[afi][i],
old_vrf_id)) {
if ((old_vrf_id == VRF_UNKNOWN)
|| vrf_bitmap_check(zclient->redist[afi][i],
old_vrf_id)) {
vrf_bitmap_unset(zclient->redist[afi][i],
old_vrf_id);
vrf_bitmap_set(zclient->redist[afi][i],
@ -1550,7 +1579,7 @@ void bgp_zebra_instance_register(struct bgp *bgp)
/* For default instance, register to learn about VNIs, if appropriate.
*/
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
&& bgp->advertise_all_vni)
&& is_evpn_enabled())
bgp_zebra_advertise_all_vni(bgp, 1);
}
@ -1569,7 +1598,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp)
/* For default instance, unregister learning about VNIs, if appropriate.
*/
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
&& bgp->advertise_all_vni)
&& is_evpn_enabled())
bgp_zebra_advertise_all_vni(bgp, 0);
/* Deregister for router-id, interfaces, redistributed routes. */
@ -1675,6 +1704,39 @@ static void bgp_zebra_connected(struct zclient *zclient)
*/
}
static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
char buf[ETHER_ADDR_STRLEN];
vni_t l3vni = 0;
struct ethaddr rmac;
struct in_addr originator_ip;
struct stream *s;
memset(&rmac, 0, sizeof(struct ethaddr));
memset(&originator_ip, 0, sizeof(struct in_addr));
s = zclient->ibuf;
l3vni = stream_getl(s);
if (cmd == ZEBRA_L3VNI_ADD) {
stream_get(&rmac, s, sizeof(struct ethaddr));
originator_ip.s_addr = stream_get_ipv4(s);
}
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s",
(cmd == ZEBRA_L3VNI_ADD) ? "add" : "del",
vrf_id_to_name(vrf_id),
l3vni,
prefix_mac2str(&rmac, buf, sizeof(buf)));
if (cmd == ZEBRA_L3VNI_ADD)
bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip);
else
bgp_evpn_local_l3vni_del(l3vni, vrf_id);
return 0;
}
static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
@ -1682,23 +1744,29 @@ static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
vni_t vni;
struct bgp *bgp;
struct in_addr vtep_ip;
vrf_id_t tenant_vrf_id = VRF_DEFAULT;
s = zclient->ibuf;
vni = stream_getl(s);
if (command == ZEBRA_VNI_ADD)
if (command == ZEBRA_VNI_ADD) {
vtep_ip.s_addr = stream_get_ipv4(s);
stream_get(&tenant_vrf_id, s, sizeof(vrf_id_t));
}
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx VNI %s VRF %u VNI %u",
(command == ZEBRA_VNI_ADD) ? "add" : "del", vrf_id,
vni);
zlog_debug("Rx VNI %s VRF %s VNI %u tenant-vrf %s",
(command == ZEBRA_VNI_ADD) ? "add" : "del",
vrf_id_to_name(vrf_id),
vni, vrf_id_to_name(tenant_vrf_id));
if (command == ZEBRA_VNI_ADD)
return bgp_evpn_local_vni_add(
bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id);
bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id,
tenant_vrf_id);
else
return bgp_evpn_local_vni_del(bgp, vni);
}
@ -1782,6 +1850,8 @@ void bgp_zebra_init(struct thread_master *master)
zclient->local_vni_del = bgp_zebra_process_local_vni;
zclient->local_macip_add = bgp_zebra_process_local_macip;
zclient->local_macip_del = bgp_zebra_process_local_macip;
zclient->local_l3vni_add = bgp_zebra_process_local_l3vni;
zclient->local_l3vni_del = bgp_zebra_process_local_l3vni;
}
void bgp_zebra_destroy(void)

View File

@ -24,6 +24,7 @@
#include "thread.h"
#include "buffer.h"
#include "stream.h"
#include "ringbuf.h"
#include "command.h"
#include "sockunion.h"
#include "sockopt.h"
@ -78,7 +79,7 @@
#include "bgpd/bgp_evpn_vty.h"
#include "bgpd/bgp_keepalives.h"
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_ecommunity.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_QOBJ_TYPE(bgp_master)
@ -217,7 +218,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
return 0;
/* EVPN uses router id in RD, withdraw them */
if (bgp->advertise_all_vni)
if (is_evpn_enabled())
bgp_evpn_handle_router_id_update(bgp, TRUE);
IPV4_ADDR_COPY(&bgp->router_id, id);
@ -234,7 +235,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
}
/* EVPN uses router id in RD, update them */
if (bgp->advertise_all_vni)
if (is_evpn_enabled())
bgp_evpn_handle_router_id_update(bgp, FALSE);
return 0;
@ -865,8 +866,7 @@ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi)
/* peer global config reset */
static void peer_global_config_reset(struct peer *peer)
{
int v6only;
int saved_flags = 0;
peer->change_local_as = 0;
peer->ttl = (peer_sort(peer) == BGP_PEER_IBGP ? MAXTTL : 1);
@ -884,13 +884,11 @@ static void peer_global_config_reset(struct peer *peer)
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
/* This is a per-peer specific flag and so we must preserve it */
v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
/* These are per-peer specific flags and so we must preserve them */
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
peer->flags = 0;
if (v6only)
SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
SET_FLAG(peer->flags, saved_flags);
peer->config = 0;
peer->holdtime = 0;
@ -912,7 +910,7 @@ static void peer_global_config_reset(struct peer *peer)
}
/* Check peer's AS number and determines if this peer is IBGP or EBGP */
static bgp_peer_sort_t peer_calc_sort(struct peer *peer)
static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
{
struct bgp *bgp;
@ -1150,19 +1148,19 @@ struct peer *peer_new(struct bgp *bgp)
* - We RX a BGP_UPDATE where the attributes alone are just
* under BGP_MAX_PACKET_SIZE
* - The user configures an outbound route-map that does many as-path
* prepends or adds many communities. At most they can have
* CMD_ARGC_MAX
* args in a route-map so there is a finite limit on how large they
* can
* make the attributes.
* prepends or adds many communities. At most they can have
* CMD_ARGC_MAX args in a route-map so there is a finite limit on how
* large they can make the attributes.
*
* Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
* bounds
* checking for every single attribute as we construct an UPDATE.
* bounds checking for every single attribute as we construct an
* UPDATE.
*/
peer->obuf_work =
stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
peer->ibuf_work = stream_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
peer->ibuf_work =
ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
bgp_sync_init(peer);
@ -1204,7 +1202,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
peer_dst->local_as = peer_src->local_as;
peer_dst->ifindex = peer_src->ifindex;
peer_dst->port = peer_src->port;
peer_sort(peer_dst);
(void)peer_sort(peer_dst);
peer_dst->rmap_type = peer_src->rmap_type;
/* Timers */
@ -1475,9 +1473,12 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
hash_get(bgp->peerhash, peer, hash_alloc_intern);
/* Adjust update-group coalesce timer heuristics for # peers. */
long ct = BGP_DEFAULT_SUBGROUP_COALESCE_TIME
+ (bgp->peer->count * BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME);
bgp->coalesce_time = MIN(BGP_MAX_SUBGROUP_COALESCE_TIME, ct);
if (bgp->heuristic_coalesce) {
long ct = BGP_DEFAULT_SUBGROUP_COALESCE_TIME
+ (bgp->peer->count
* BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME);
bgp->coalesce_time = MIN(BGP_MAX_SUBGROUP_COALESCE_TIME, ct);
}
active = peer_active(peer);
@ -1494,8 +1495,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
peer_af_create(peer, afi, safi);
}
/* auto shutdown if configured */
if (bgp->autoshutdown)
peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
/* Set up peer's events and timers. */
if (!active && peer_active(peer))
else if (!active && peer_active(peer))
bgp_timer_set(peer);
return peer;
@ -2176,7 +2180,7 @@ int peer_delete(struct peer *peer)
}
if (peer->ibuf_work) {
stream_free(peer->ibuf_work);
ringbuf_del(peer->ibuf_work);
peer->ibuf_work = NULL;
}
@ -2336,7 +2340,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
struct peer *peer)
{
struct peer *conf;
int v6only;
int saved_flags = 0;
conf = group->conf;
@ -2354,14 +2358,11 @@ static void peer_group2peer_config_copy(struct peer_group *group,
/* GTSM hops */
peer->gtsm_hops = conf->gtsm_hops;
/* this flag is per-neighbor and so has to be preserved */
v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
/* peer flags apply */
/* These are per-peer specific flags and so we must preserve them */
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
peer->flags = conf->flags;
if (v6only)
SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
SET_FLAG(peer->flags, saved_flags);
/* peer config apply */
peer->config = conf->config;
@ -3139,6 +3140,9 @@ int bgp_delete(struct bgp *bgp)
bgp->name);
}
/* unmap from RT list */
bgp_evpn_vrf_delete(bgp);
/* Stop timers. */
if (bgp->t_rmap_def_originate_eval) {
BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
@ -7077,6 +7081,11 @@ int bgp_config_write(struct vty *vty)
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
/* skip all auto created vrf as they dont have user config */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
continue;
/* Router bgp ASN */
vty_out(vty, "router bgp %u", bgp->as);
@ -7140,6 +7149,10 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n",
bgp->default_subgroup_pkt_queue_max);
/* BGP default autoshutdown neighbors */
if (bgp->autoshutdown)
vty_out(vty, " bgp default auto-shutdown\n");
/* BGP client-to-client reflection. */
if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
vty_out(vty, " no bgp client-to-client reflection\n");
@ -7301,6 +7314,38 @@ int bgp_config_write(struct vty *vty)
if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
vty_out(vty, " no auto-summary\n");
/* import route-target */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
char *ecom_str;
struct listnode *node, *nnode;
struct ecommunity *ecom;
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
ecom)) {
ecom_str = ecommunity_ecom2str(
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " route-target import %s\n",
ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
}
/* export route-target */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
char *ecom_str;
struct listnode *node, *nnode;
struct ecommunity *ecom;
for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
ecom)) {
ecom_str = ecommunity_ecom2str(
ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " route-target export %s\n",
ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
}
/* IPv4 unicast configuration. */
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
@ -7361,6 +7406,13 @@ void bgp_master_init(struct thread_master *master)
bgp_process_queue_init();
/* init the rd id space.
assign 0th index in the bitfield,
so that we start with id 1
*/
bf_init(bm->rd_idspace, UINT16_MAX);
bf_assign_zero_index(bm->rd_idspace);
/* Enable multiple instances by default. */
bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
@ -7418,24 +7470,33 @@ static void bgp_pthreads_init()
{
frr_pthread_init();
frr_pthread_new("BGP i/o thread", PTHREAD_IO, bgp_io_start,
bgp_io_stop);
frr_pthread_new("BGP keepalives thread", PTHREAD_KEEPALIVES,
bgp_keepalives_start, bgp_keepalives_stop);
/* pre-run initialization */
bgp_keepalives_init();
bgp_io_init();
struct frr_pthread_attr io = {
.id = PTHREAD_IO,
.start = frr_pthread_attr_default.start,
.stop = frr_pthread_attr_default.stop,
.name = "BGP I/O thread",
};
struct frr_pthread_attr ka = {
.id = PTHREAD_KEEPALIVES,
.start = bgp_keepalives_start,
.stop = bgp_keepalives_stop,
.name = "BGP Keepalives thread",
};
frr_pthread_new(&io);
frr_pthread_new(&ka);
}
void bgp_pthreads_run()
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
struct frr_pthread *io = frr_pthread_get(PTHREAD_IO);
struct frr_pthread *ka = frr_pthread_get(PTHREAD_KEEPALIVES);
frr_pthread_run(PTHREAD_IO, &attr, NULL);
frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL);
frr_pthread_run(io, NULL);
frr_pthread_run(ka, NULL);
/* Wait until threads are ready. */
frr_pthread_wait_running(io);
frr_pthread_wait_running(ka);
}
void bgp_pthreads_finish()
@ -7517,6 +7578,7 @@ void bgp_terminate(void)
*/
/* reverse bgp_master_init */
bgp_close();
if (bm->listen_sockets)
list_delete_and_null(&bm->listen_sockets);

View File

@ -36,6 +36,7 @@
#include "defaults.h"
#include "bgp_memory.h"
#include "bitfield.h"
#include "vxlan.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
@ -136,6 +137,9 @@ struct bgp_master {
/* clang-format off */
#define RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
/* Id space for automatic RD derivation for an EVI/VRF */
bitfield_t rd_idspace;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgp_master)
@ -381,7 +385,13 @@ struct bgp {
_Atomic uint32_t wpkt_quanta; // max # packets to write per i/o cycle
_Atomic uint32_t rpkt_quanta; // max # packets to read per i/o cycle
u_int32_t coalesce_time;
/* Automatic coalesce adjust on/off */
bool heuristic_coalesce;
/* Actual coalesce time */
uint32_t coalesce_time;
/* Auto-shutdown new peers */
bool autoshutdown;
u_int32_t addpath_tx_id;
int addpath_tx_used[AFI_MAX][SAFI_MAX];
@ -405,8 +415,41 @@ struct bgp {
/* Hash table of Import RTs to EVIs */
struct hash *import_rt_hash;
/* Id space for automatic RD derivation for an EVI */
bitfield_t rd_idspace;
/* Hash table of VRF import RTs to VRFs */
struct hash *vrf_import_rt_hash;
/* L3-VNI corresponding to this vrf */
vni_t l3vni;
/* router-mac to be used in mac-ip routes for this vrf */
struct ethaddr rmac;
/* originator ip - to be used as NH for type-5 routes */
struct in_addr originator_ip;
/* vrf flags */
uint32_t vrf_flags;
#define BGP_VRF_AUTO (1 << 0)
#define BGP_VRF_ADVERTISE_IPV4_IN_EVPN (1 << 1)
#define BGP_VRF_ADVERTISE_IPV6_IN_EVPN (1 << 2)
#define BGP_VRF_IMPORT_RT_CFGD (1 << 3)
#define BGP_VRF_EXPORT_RT_CFGD (1 << 4)
#define BGP_VRF_RD_CFGD (1 << 5)
/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;
/* RD for this VRF */
struct prefix_rd vrf_prd;
/* import rt list for the vrf instance */
struct list *vrf_import_rtl;
/* export rt list for the vrf instance */
struct list *vrf_export_rtl;
/* list of corresponding l2vnis (struct bgpevpn) */
struct list *l2vnis;
QOBJ_FIELDS
};
@ -595,8 +638,8 @@ struct peer {
struct stream_fifo *ibuf; // packets waiting to be processed
struct stream_fifo *obuf; // packets waiting to be written
struct stream *ibuf_work; // WiP buffer used by bgp_read() only
struct stream *obuf_work; // WiP buffer used to construct packets
struct ringbuf *ibuf_work; // WiP buffer used by bgp_read() only
struct stream *obuf_work; // WiP buffer used to construct packets
struct stream *curr; // the current packet being parsed
@ -826,6 +869,22 @@ struct peer {
/* workqueues */
struct work_queue *clear_node_queue;
#define PEER_TOTAL_RX(peer) \
atomic_load_explicit(&peer->open_in, memory_order_relaxed) + \
atomic_load_explicit(&peer->update_in, memory_order_relaxed) + \
atomic_load_explicit(&peer->notify_in, memory_order_relaxed) + \
atomic_load_explicit(&peer->refresh_in, memory_order_relaxed) + \
atomic_load_explicit(&peer->keepalive_in, memory_order_relaxed) + \
atomic_load_explicit(&peer->dynamic_cap_in, memory_order_relaxed)
#define PEER_TOTAL_TX(peer) \
atomic_load_explicit(&peer->open_out, memory_order_relaxed) + \
atomic_load_explicit(&peer->update_out, memory_order_relaxed) + \
atomic_load_explicit(&peer->notify_out, memory_order_relaxed) + \
atomic_load_explicit(&peer->refresh_out, memory_order_relaxed) + \
atomic_load_explicit(&peer->keepalive_out, memory_order_relaxed) + \
atomic_load_explicit(&peer->dynamic_cap_out, memory_order_relaxed)
/* Statistics field */
_Atomic uint32_t open_in; /* Open message input count */
_Atomic uint32_t open_out; /* Open message output count */
@ -860,9 +919,6 @@ struct peer {
/* Send prefix count. */
unsigned long scount[AFI_MAX][SAFI_MAX];
/* Announcement attribute hash. */
struct hash *hash[AFI_MAX][SAFI_MAX];
/* Notify data. */
struct bgp_notify notify;
@ -1017,6 +1073,7 @@ struct bgp_nlri {
#define BGP_ATTR_AS4_PATH 17
#define BGP_ATTR_AS4_AGGREGATOR 18
#define BGP_ATTR_AS_PATHLIMIT 21
#define BGP_ATTR_PMSI_TUNNEL 22
#define BGP_ATTR_ENCAP 23
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_PREFIX_SID 40

View File

@ -170,12 +170,12 @@ struct rfapi_nve_group_cfg *bgp_rfapi_cfg_match_group(struct rfapi_cfg *hc,
#if BGP_VNC_DEBUG_MATCH_GROUP
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(vn, buf, BUFSIZ);
prefix2str(vn, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: vn prefix: %s", __func__, buf);
prefix2str(un, buf, BUFSIZ);
prefix2str(un, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: un prefix: %s", __func__, buf);
vnc_zlog_debug_verbose(
@ -1626,7 +1626,11 @@ DEFUN (vnc_nve_group_export_no_prefixlist,
return CMD_WARNING_CONFIG_FAILED;
}
argv_find_and_parse_afi(argv, argc, &idx, &afi);
if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
vty_out(vty, "%% Malformed Address Family\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (argv[idx-1]->text[0] == 'z')
is_bgp = 0;
idx += 2; /* skip afi and keyword */
@ -1691,7 +1695,11 @@ DEFUN (vnc_nve_group_export_prefixlist,
return CMD_WARNING_CONFIG_FAILED;
}
argv_find_and_parse_afi(argv, argc, &idx, &afi);
if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
vty_out(vty, "%% Malformed Address Family\n");
return CMD_WARNING_CONFIG_FAILED;
}
if (argv[idx-1]->text[0] == 'z')
is_bgp = 0;
idx = argc - 1;
@ -3884,8 +3892,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
}
if (rfg->rd.prefixlen) {
char buf[BUFSIZ];
buf[0] = buf[BUFSIZ - 1] = 0;
char buf[RD_ADDRSTRLEN];
if (AF_UNIX == rfg->rd.family) {
@ -3898,18 +3905,10 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty_out(vty, " rd auto:nh:%d\n",
value);
} else {
if (!prefix_rd2str(&rfg->rd, buf,
BUFSIZ)
|| !buf[0] || buf[BUFSIZ - 1]) {
vty_out(vty,
"!Error: Can't convert rd\n");
} else {
vty_out(vty, " rd %s\n", buf);
}
}
} else
vty_out(vty, " rd %s\n",
prefix_rd2str(&rfg->rd, buf,
sizeof(buf)));
}
if (rfg->rt_import_list && rfg->rt_export_list
@ -4098,7 +4097,8 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
}
}
if (hc->default_rd.prefixlen || hc->default_response_lifetime
if (hc->default_rd.prefixlen
|| hc->default_response_lifetime != BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
|| hc->default_rt_import_list || hc->default_rt_export_list
|| hc->nve_groups_sequential->count) {
@ -4107,8 +4107,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty_out(vty, " vnc defaults\n");
if (hc->default_rd.prefixlen) {
char buf[BUFSIZ];
buf[0] = buf[BUFSIZ - 1] = 0;
char buf[RD_ADDRSTRLEN];
if (AF_UNIX == hc->default_rd.family) {
uint16_t value = 0;
@ -4121,20 +4120,14 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty_out(vty, " rd auto:vn:%d\n",
value);
} else {
if (!prefix_rd2str(&hc->default_rd, buf,
BUFSIZ)
|| !buf[0] || buf[BUFSIZ - 1]) {
vty_out(vty,
"!Error: Can't convert rd\n");
} else {
vty_out(vty, " rd %s\n", buf);
}
}
} else
vty_out(vty, " rd %s\n",
prefix_rd2str(&hc->default_rd,
buf,
sizeof(buf)));
}
if (hc->default_response_lifetime) {
if (hc->default_response_lifetime
!= BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT) {
vty_out(vty, " response-lifetime ");
if (hc->default_response_lifetime != UINT32_MAX)
vty_out(vty, "%d",
@ -4187,38 +4180,26 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty_out(vty, " vnc nve-group %s\n", rfg->name);
if (rfg->vn_prefix.family && rfg->vn_node) {
char buf[BUFSIZ];
buf[0] = buf[BUFSIZ - 1] = 0;
char buf[PREFIX_STRLEN];
prefix2str(&rfg->vn_prefix, buf,
BUFSIZ);
if (!buf[0] || buf[BUFSIZ - 1]) {
vty_out(vty,
"!Error: Can't convert prefix\n");
} else {
vty_out(vty, " prefix %s %s\n",
"vn", buf);
}
sizeof(buf));
vty_out(vty, " prefix %s %s\n",
"vn", buf);
}
if (rfg->un_prefix.family && rfg->un_node) {
char buf[BUFSIZ];
buf[0] = buf[BUFSIZ - 1] = 0;
char buf[PREFIX_STRLEN];
prefix2str(&rfg->un_prefix, buf,
BUFSIZ);
if (!buf[0] || buf[BUFSIZ - 1]) {
vty_out(vty,
"!Error: Can't convert prefix\n");
} else {
vty_out(vty, " prefix %s %s\n",
"un", buf);
}
sizeof(buf));
vty_out(vty, " prefix %s %s\n",
"un", buf);
}
if (rfg->rd.prefixlen) {
char buf[BUFSIZ];
buf[0] = buf[BUFSIZ - 1] = 0;
char buf[RD_ADDRSTRLEN];
if (AF_UNIX == rfg->rd.family) {
@ -4233,21 +4214,12 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
" rd auto:vn:%d\n",
value);
} else {
if (!prefix_rd2str(&rfg->rd,
buf, BUFSIZ)
|| !buf[0]
|| buf[BUFSIZ - 1]) {
vty_out(vty,
"!Error: Can't convert rd\n");
} else {
vty_out(vty,
" rd %s\n",
buf);
}
}
} else
vty_out(vty,
" rd %s\n",
prefix_rd2str(&rfg->rd,
buf,
sizeof(buf)));
}
if (rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME) {
vty_out(vty, " response-lifetime ");

View File

@ -31,6 +31,7 @@
#include "lib/linklist.h"
#include "lib/command.h"
#include "lib/stream.h"
#include "lib/ringbuf.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
@ -363,15 +364,11 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
afi_t afi; /* of the VN address */
struct bgp_node *bn;
struct bgp_info *bi;
char buf[BUFSIZ];
char buf2[BUFSIZ];
char buf[PREFIX_STRLEN];
char buf2[RD_ADDRSTRLEN];
struct prefix_rd prd0;
prefix2str(p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix_rd2str(prd, buf2, BUFSIZ);
buf2[BUFSIZ - 1] = 0;
prefix2str(p, buf, sizeof(buf));
afi = family2afi(p->family);
assert(afi == AFI_IP || afi == AFI_IP6);
@ -386,7 +383,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
vnc_zlog_debug_verbose(
"%s: peer=%p, prefix=%s, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
__func__, peer, buf, buf2, afi, safi, bn,
__func__, peer, buf,
prefix_rd2str(prd, buf2, sizeof(buf2)), afi, safi, bn,
(bn ? bn->info : NULL));
for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
@ -464,11 +462,9 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
rfapiProcessWithdraw(peer, rfd, p, prd, NULL, afi, safi, type, kill);
if (bi) {
char buf[BUFSIZ];
prefix2str(p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
char buf[PREFIX_STRLEN];
prefix2str(p, buf, sizeof(buf));
vnc_zlog_debug_verbose(
"%s: Found route (safi=%d) to delete at prefix %s",
__func__, safi, buf);
@ -593,8 +589,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
uint32_t label_val;
struct bgp_attr_encap_subtlv *encaptlv;
char buf[BUFSIZ];
char buf2[BUFSIZ];
char buf[PREFIX_STRLEN];
char buf2[RD_ADDRSTRLEN];
#if 0 /* unused? */
struct prefix pfx_buf;
#endif
@ -650,9 +646,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
else
label_val = MPLS_LABEL_IMPLICIT_NULL;
prefix_rd2str(prd, buf2, BUFSIZ);
buf2[BUFSIZ - 1] = 0;
prefix_rd2str(prd, buf2, sizeof(buf2));
afi = family2afi(p->family);
assert(afi == AFI_IP || afi == AFI_IP6);
@ -907,8 +901,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
}
prefix2str(p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix2str(p, buf, sizeof(buf));
/*
* At this point:
@ -920,7 +913,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
* aspath: points to interned hash from aspath hash table
*/
red = bgp_redist_lookup(bgp, afi, type, VRF_DEFAULT);
red = bgp_redist_lookup(bgp, afi, type, 0);
if (red && red->redist_metric_flag) {
attr.med = red->redist_metric;
@ -1318,7 +1311,7 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
stream_fifo_free(rfd->peer->obuf);
if (rfd->peer->ibuf_work)
stream_free(rfd->peer->ibuf_work);
ringbuf_del(rfd->peer->ibuf_work);
if (rfd->peer->obuf_work)
stream_free(rfd->peer->obuf_work);
@ -1611,11 +1604,10 @@ rfapi_query_inner(void *handle, struct rfapi_ip_addr *target,
}
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
char *s;
prefix2str(&p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix2str(&p, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s(rfd=%p, target=%s, ppNextHop=%p)",
__func__, rfd, buf, ppNextHopEntry);
@ -2434,10 +2426,9 @@ int rfapi_register(void *handle, struct rfapi_ip_prefix *prefix,
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix2str(&p, buf, sizeof(buf));
vnc_zlog_debug_verbose(
"%s(rfd=%p, pfx=%s, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
__func__, rfd, buf, lifetime, options_un, options_vn,
@ -3841,12 +3832,10 @@ int rfapi_set_autord_from_vn(struct prefix_rd *rd, struct rfapi_ip_addr *vn)
4); /* low order 4 bytes */
}
{
char buf[BUFSIZ];
buf[0] = 0;
prefix_rd2str(rd, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
char buf[RD_ADDRSTRLEN];
vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__,
buf);
prefix_rd2str(rd, buf, sizeof(buf)));
}
return 0;
}

View File

@ -41,6 +41,7 @@
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
#include "bgpd/bgp_vnc_types.h"
#include "bgpd/bgp_rd.h"
#include "bgpd/rfapi/rfapi.h"
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
@ -645,10 +646,9 @@ rfapiMonitorMoveShorter(struct route_node *original_vpn_node, int lockoffset)
#if DEBUG_MONITOR_MOVE_SHORTER
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&original_vpn_node->p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(&original_vpn_node->p, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__,
buf);
}
@ -779,10 +779,9 @@ rfapiMonitorMoveShorter(struct route_node *original_vpn_node, int lockoffset)
#if DEBUG_MONITOR_MOVE_SHORTER
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&par->p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(&par->p, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: moved to node pfx=%s", __func__,
buf);
}
@ -1452,7 +1451,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
__func__, __LINE__, have_vnc_tunnel_un);
#endif
if (!have_vnc_tunnel_un && bi && bi->extra) {
if (!have_vnc_tunnel_un && bi->extra) {
/*
* use cached UN address from ENCAP route
*/
@ -1594,10 +1593,9 @@ static int rfapiNhlAddNodeRoutes(
}
if (!skiplist_search(seen_nexthops, &pfx_vn, NULL)) {
#if DEBUG_RETURNED_NHL
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&pfx_vn, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix2str(&pfx_vn, buf, sizeof(buf));
vnc_zlog_debug_verbose(
"%s: already put VN/nexthop %s, skip", __func__,
buf);
@ -1760,10 +1758,9 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
#if DEBUG_RETURNED_NHL
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&rn->p, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(&rn->p, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__,
buf);
}
@ -2136,10 +2133,12 @@ static void rfapiItBiIndexAdd(struct route_node *rn, /* Import table VPN node */
assert(bi->extra);
{
char buf[BUFSIZ];
prefix_rd2str(&bi->extra->vnc.import.rd, buf, BUFSIZ);
char buf[RD_ADDRSTRLEN];
vnc_zlog_debug_verbose("%s: bi %p, peer %p, rd %s", __func__,
bi, bi->peer, buf);
bi, bi->peer,
prefix_rd2str(&bi->extra->vnc.import.rd,
buf, sizeof(buf)));
}
sl = RFAPI_RDINDEX_W_ALLOC(rn);
@ -2173,18 +2172,15 @@ static void rfapiItBiIndexDump(struct route_node *rn)
for (rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor); !rc;
rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor)) {
char buf[BUFSIZ];
char buf_aux_pfx[BUFSIZ];
char buf[RD_ADDRSTRLEN];
char buf_aux_pfx[PREFIX_STRLEN];
prefix_rd2str(&k->extra->vnc.import.rd, buf, BUFSIZ);
buf_aux_pfx[0] = 0;
prefix_rd2str(&k->extra->vnc.import.rd, buf, sizeof(buf));
if (k->extra->vnc.import.aux_prefix.family) {
prefix2str(&k->extra->vnc.import.aux_prefix,
buf_aux_pfx, BUFSIZ);
} else {
strncpy(buf_aux_pfx, "(none)", BUFSIZ);
buf_aux_pfx[BUFSIZ - 1] = 0;
}
buf_aux_pfx, sizeof(buf_aux_pfx));
} else
strncpy(buf_aux_pfx, "(none)", PREFIX_STRLEN);
vnc_zlog_debug_verbose("bi %p, peer %p, rd %s, aux_prefix %s",
k, k->peer, buf, buf_aux_pfx);
@ -2208,19 +2204,19 @@ static struct bgp_info *rfapiItBiIndexSearch(
#if DEBUG_BI_SEARCH
{
char buf[BUFSIZ];
char buf_aux_pfx[BUFSIZ];
char buf[RD_ADDRSTRLEN];
char buf_aux_pfx[PREFIX_STRLEN];
prefix_rd2str(prd, buf, BUFSIZ);
if (aux_prefix) {
prefix2str(aux_prefix, buf_aux_pfx, BUFSIZ);
} else {
strncpy(buf_aux_pfx, "(nil)", BUFSIZ - 1);
buf_aux_pfx[BUFSIZ - 1] = 0;
}
prefix2str(aux_prefix, buf_aux_pfx,
sizeof(buf_aux_pfx));
} else
strncpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s",
__func__, buf, peer, buf_aux_pfx);
__func__,
prefix_rd2str(prd, buf, sizeof(buf)),
peer, buf_aux_pfx);
rfapiItBiIndexDump(rn);
}
#endif
@ -2235,12 +2231,14 @@ static struct bgp_info *rfapiItBiIndexSearch(
bi_result = bi_result->next) {
#if DEBUG_BI_SEARCH
{
char buf[BUFSIZ];
prefix_rd2str(&bi_result->extra->vnc.import.rd,
buf, BUFSIZ);
char buf[RD_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"%s: bi has prd=%s, peer=%p", __func__,
buf, bi_result->peer);
prefix_rd2str(&bi_result->extra->vnc.import.rd,
buf,
sizeof(buf)),
bi_result->peer);
}
#endif
if (peer == bi_result->peer
@ -2303,10 +2301,12 @@ static void rfapiItBiIndexDel(struct route_node *rn, /* Import table VPN node */
int rc;
{
char buf[BUFSIZ];
prefix_rd2str(&bi->extra->vnc.import.rd, buf, BUFSIZ);
char buf[RD_ADDRSTRLEN];
vnc_zlog_debug_verbose("%s: bi %p, peer %p, rd %s", __func__,
bi, bi->peer, buf);
bi, bi->peer,
prefix_rd2str(&bi->extra->vnc.import.rd,
buf, sizeof(buf)));
}
sl = RFAPI_RDINDEX(rn);
@ -3671,9 +3671,9 @@ void rfapiBgpInfoFilteredImportVPN(
rfapiCopyUnEncap2VPN(ern->info, info_new);
route_unlock_node(ern); /* undo lock in route_note_match */
} else {
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&vn_prefix, buf, sizeof(buf));
buf[BUFSIZ - 1] = 0;
/* Not a big deal, just means VPN route got here first */
vnc_zlog_debug_verbose("%s: no encap route for vn addr %s",
__func__, buf);
@ -3947,7 +3947,7 @@ void rfapiProcessUpdate(struct peer *peer,
vnc_zlog_debug_verbose(
"%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
__func__, rc, lni, attr);
if (attr && !rc) {
if (!rc) {
it = rfapiMacImportTableGet(bgp, lni);
rfapiBgpInfoFilteredImportVPN(
@ -4433,10 +4433,10 @@ static void rfapiDeleteRemotePrefixesIt(
#if DEBUG_L2_EXTRA
{
char buf_pfx[BUFSIZ];
char buf_pfx[PREFIX_STRLEN];
if (p) {
prefix2str(p, buf_pfx, BUFSIZ);
prefix2str(p, buf_pfx, sizeof(buf_pfx));
} else {
buf_pfx[0] = '*';
buf_pfx[1] = 0;
@ -4469,11 +4469,11 @@ static void rfapiDeleteRemotePrefixesIt(
struct bgp_info *next;
if (VNC_DEBUG(IMPORT_DEL_REMOTE)) {
char p1line[BUFSIZ];
char p2line[BUFSIZ];
char p1line[PREFIX_STRLEN];
char p2line[PREFIX_STRLEN];
prefix2str(p, p1line, BUFSIZ);
prefix2str(&rn->p, p2line, BUFSIZ);
prefix2str(p, p1line, sizeof(p1line));
prefix2str(&rn->p, p2line, sizeof(p2line));
vnc_zlog_debug_any("%s: want %s, have %s",
__func__, p1line, p2line);
}
@ -4482,8 +4482,9 @@ static void rfapiDeleteRemotePrefixesIt(
continue;
{
char buf_pfx[BUFSIZ];
prefix2str(&rn->p, buf_pfx, BUFSIZ);
char buf_pfx[PREFIX_STRLEN];
prefix2str(&rn->p, buf_pfx, sizeof(buf_pfx));
vnc_zlog_debug_verbose("%s: rn pfx=%s",
__func__, buf_pfx);
}

View File

@ -839,7 +839,7 @@ void rfapiMonitorItNodeChanged(
struct bgp *bgp = bgp_get_default();
afi_t afi = family2afi(rn->p.family);
#if DEBUG_L2_EXTRA
char buf_prefix[BUFSIZ];
char buf_prefix[PREFIX_STRLEN];
#endif
assert(bgp);
@ -848,7 +848,7 @@ void rfapiMonitorItNodeChanged(
nves_seen = skiplist_new(0, NULL, NULL);
#if DEBUG_L2_EXTRA
prefix2str(&it_node->p, buf_prefix, BUFSIZ);
prefix2str(&it_node->p, buf_prefix, sizeof(buf_prefix));
vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%s",
__func__, import_table, it_node, buf_prefix);
#endif
@ -926,22 +926,20 @@ void rfapiMonitorItNodeChanged(
assert(!skiplist_insert(nves_seen,
m->rfd, NULL));
{
char buf_attach_pfx[BUFSIZ];
char buf_target_pfx[BUFSIZ];
char buf_attach_pfx[PREFIX_STRLEN];
char buf_target_pfx[PREFIX_STRLEN];
prefix2str(&m->node->p,
buf_attach_pfx,
BUFSIZ);
prefix2str(&m->p,
buf_target_pfx,
BUFSIZ);
vnc_zlog_debug_verbose(
"%s: update rfd %p attached to pfx %s (targ=%s)",
__func__, m->rfd,
buf_attach_pfx,
buf_target_pfx);
}
prefix2str(&m->node->p,
buf_attach_pfx,
sizeof(buf_attach_pfx));
prefix2str(&m->p,
buf_target_pfx,
sizeof(buf_target_pfx));
vnc_zlog_debug_verbose(
"%s: update rfd %p attached to pfx %s (targ=%s)",
__func__, m->rfd,
buf_attach_pfx,
buf_target_pfx);
/*
* update its RIB
@ -1271,8 +1269,9 @@ static void rfapiMonitorEthDetachImport(
assert(rn);
#if DEBUG_L2_EXTRA
char buf_prefix[BUFSIZ];
prefix2str(&rn->p, buf_prefix, BUFSIZ);
char buf_prefix[PREFIX_STRLEN];
prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
#endif
/*

View File

@ -207,7 +207,7 @@ void rfapiRibCheckCounts(
}
}
if (checkstats && bgp && bgp->rfapi) {
if (checkstats && bgp->rfapi) {
if (t_pfx_active != bgp->rfapi->rib_prefix_count_total) {
vnc_zlog_debug_verbose(
"%s: actual total pfx count %u != running %u",
@ -342,7 +342,7 @@ rfapiRibStartTimer(struct rfapi_descriptor *rfd, struct rfapi_info *ri,
{
struct thread *t = ri->timer;
struct rfapi_rib_tcb *tcb = NULL;
char buf_prefix[BUFSIZ];
char buf_prefix[PREFIX_STRLEN];
if (t) {
tcb = t->arg;
@ -363,7 +363,7 @@ rfapiRibStartTimer(struct rfapi_descriptor *rfd, struct rfapi_info *ri,
UNSET_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED);
}
prefix2str(&rn->p, buf_prefix, BUFSIZ);
prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
vnc_zlog_debug_verbose("%s: rfd %p pfx %s life %u", __func__, rfd,
buf_prefix, ri->lifetime);
ri->timer = NULL;
@ -688,13 +688,10 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
memcpy(&vo->v.l2addr.macaddr, bi->extra->vnc.import.rd.val + 2,
ETH_ALEN);
if (bi->attr) {
(void)rfapiEcommunityGetLNI(
bi->attr->ecommunity,
&vo->v.l2addr.logical_net_id);
(void)rfapiEcommunityGetEthernetTag(
bi->attr->ecommunity, &vo->v.l2addr.tag_id);
}
(void)rfapiEcommunityGetLNI(bi->attr->ecommunity,
&vo->v.l2addr.logical_net_id);
(void)rfapiEcommunityGetEthernetTag(bi->attr->ecommunity,
&vo->v.l2addr.tag_id);
/* local_nve_id comes from RD */
vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
@ -710,7 +707,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
/*
* If there is an auxiliary IP address (L2 can have it), copy it
*/
if (bi && bi->extra && bi->extra->vnc.import.aux_prefix.family) {
if (bi->extra && bi->extra->vnc.import.aux_prefix.family) {
ri->rk.aux_prefix = bi->extra->vnc.import.aux_prefix;
}
}
@ -855,7 +852,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
struct list *lPendCost = NULL;
struct list *delete_list = NULL;
int printedprefix = 0;
char buf_prefix[BUFSIZ];
char buf_prefix[PREFIX_STRLEN];
int rib_node_started_nonempty = 0;
int sendingsomeroutes = 0;
@ -866,7 +863,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
#endif
assert(pn);
prefix2str(&pn->p, buf_prefix, BUFSIZ);
prefix2str(&pn->p, buf_prefix, sizeof(buf_prefix));
vnc_zlog_debug_verbose("%s: afi=%d, %s pn->info=%p", __func__, afi,
buf_prefix, pn->info);
@ -916,8 +913,8 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
while (0
== skiplist_first(slRibPt, NULL, (void **)&ri)) {
char buf[BUFSIZ];
char buf2[BUFSIZ];
char buf[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
listnode_add(delete_list, ri);
vnc_zlog_debug_verbose(
@ -935,8 +932,8 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
ri->timer = NULL;
}
prefix2str(&ri->rk.vn, buf, BUFSIZ);
prefix2str(&ri->un, buf2, BUFSIZ);
prefix2str(&ri->rk.vn, buf, sizeof(buf));
prefix2str(&ri->un, buf2, sizeof(buf2));
vnc_zlog_debug_verbose(
"%s: put dl pfx=%s vn=%s un=%s cost=%d life=%d vn_options=%p",
__func__, buf_prefix, buf, buf2,
@ -1126,7 +1123,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
} else {
char buf_rd[BUFSIZ];
char buf_rd[RD_ADDRSTRLEN];
/* not found: add new route to RIB */
ori = rfapi_info_new();
@ -1405,13 +1402,14 @@ callback:
ri->last_sent_time = rfapi_time(NULL);
#if DEBUG_RIB_SL_RD
{
char buf_rd[BUFSIZ];
prefix_rd2str(&ri->rk.rd,
buf_rd,
sizeof(buf_rd));
char buf_rd[RD_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"%s: move route to recently deleted list, rd=%s",
__func__, buf_rd);
__func__,
prefix_rd2str(&ri->rk.rd,
buf_rd,
sizeof(buf_rd)));
}
#endif
@ -1595,7 +1593,7 @@ void rfapiRibUpdatePendingNode(
afi_t afi;
uint32_t queued_flag;
int count = 0;
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
vnc_zlog_debug_verbose("%s: entry", __func__);
@ -1608,7 +1606,7 @@ void rfapiRibUpdatePendingNode(
prefix = &it_node->p;
afi = family2afi(prefix->family);
prefix2str(prefix, buf, BUFSIZ);
prefix2str(prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: prefix=%s", __func__, buf);
pn = route_node_get(rfd->rib_pending[afi], prefix);
@ -1814,9 +1812,9 @@ int rfapiRibFTDFilterRecentPrefix(
#if DEBUG_FTD_FILTER_RECENT
{
char buf_pfx[BUFSIZ];
char buf_pfx[PREFIX_STRLEN];
prefix2str(&it_rn->p, buf_pfx, BUFSIZ);
prefix2str(&it_rn->p, buf_pfx, sizeof(buf_pfx));
vnc_zlog_debug_verbose("%s: prefix %s", __func__, buf_pfx);
}
#endif
@ -1978,14 +1976,15 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd,
#if DEBUG_NHL
{
char str_vn[BUFSIZ];
char str_aux_prefix[BUFSIZ];
char str_vn[PREFIX_STRLEN];
char str_aux_prefix[PREFIX_STRLEN];
str_vn[0] = 0;
str_aux_prefix[0] = 0;
prefix2str(&rk.vn, str_vn, BUFSIZ);
prefix2str(&rk.aux_prefix, str_aux_prefix, BUFSIZ);
prefix2str(&rk.vn, str_vn, sizeof(str_vn));
prefix2str(&rk.aux_prefix, str_aux_prefix,
sizeof(str_aux_prefix));
if (!rk.aux_prefix.family) {
}
@ -2075,11 +2074,11 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd,
route_unlock_node(trn);
{
char str_pfx[BUFSIZ];
char str_pfx_vn[BUFSIZ];
char str_pfx[PREFIX_STRLEN];
char str_pfx_vn[PREFIX_STRLEN];
prefix2str(&pfx, str_pfx, BUFSIZ);
prefix2str(&rk.vn, str_pfx_vn, BUFSIZ);
prefix2str(&pfx, str_pfx, sizeof(str_pfx));
prefix2str(&rk.vn, str_pfx_vn, sizeof(str_pfx_vn));
vnc_zlog_debug_verbose(
"%s: added pfx=%s nh[vn]=%s, cost=%u, lifetime=%u, allowed=%d",
__func__, str_pfx, str_pfx_vn, nhp->prefix.cost,
@ -2114,9 +2113,9 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it,
{
struct rfapi_descriptor *rfd;
struct listnode *node;
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
prefix2str(&it_node->p, buf, BUFSIZ);
prefix2str(&it_node->p, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s",
__func__, it, afi, it_node, buf);
@ -2290,21 +2289,21 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
for (rc = skiplist_next(sl, NULL, (void **)&ri, &cursor); !rc;
rc = skiplist_next(sl, NULL, (void **)&ri, &cursor)) {
char str_vn[BUFSIZ];
char str_un[BUFSIZ];
char str_vn[PREFIX_STRLEN];
char str_un[PREFIX_STRLEN];
char str_lifetime[BUFSIZ];
char str_age[BUFSIZ];
char *p;
char str_rd[BUFSIZ];
char str_rd[RD_ADDRSTRLEN];
++routes_displayed;
prefix2str(&ri->rk.vn, str_vn, BUFSIZ);
prefix2str(&ri->rk.vn, str_vn, sizeof(str_vn));
p = index(str_vn, '/');
if (p)
*p = 0;
prefix2str(&ri->un, str_un, BUFSIZ);
prefix2str(&ri->un, str_un, sizeof(str_un));
p = index(str_un, '/');
if (p)
*p = 0;
@ -2325,11 +2324,10 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
str_rd[0] = 0; /* start empty */
#if DEBUG_RIB_SL_RD
str_rd[0] = ' ';
prefix_rd2str(&ri->rk.rd, str_rd + 1, BUFSIZ - 1);
prefix_rd2str(&ri->rk.rd, str_rd, sizeof(str_rd));
#endif
fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s%s\n",
fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %s\n",
deleted ? 'r' : ' ', *printedprefix ? "" : str_pfx, str_vn,
str_un, ri->cost, str_lifetime, str_age, str_rd);
@ -2352,13 +2350,13 @@ static void rfapiRibShowRibSl(void *stream, struct prefix *pfx,
const char *vty_newline;
int nhs_displayed = 0;
char str_pfx[BUFSIZ];
char str_pfx[PREFIX_STRLEN];
int printedprefix = 0;
if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0)
return;
prefix2str(pfx, str_pfx, BUFSIZ);
prefix2str(pfx, str_pfx, sizeof(str_pfx));
nhs_displayed +=
print_rib_sl(fp, vty, out, sl, 0, str_pfx, &printedprefix);
@ -2418,7 +2416,7 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
rn = route_next(rn)) {
struct skiplist *sl;
char str_pfx[BUFSIZ];
char str_pfx[PREFIX_STRLEN];
int printedprefix = 0;
if (!show_removed)
@ -2472,7 +2470,7 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
str_un,
BUFSIZ));
}
prefix2str(&rn->p, str_pfx, BUFSIZ);
prefix2str(&rn->p, str_pfx, sizeof(str_pfx));
// fp(out, " %s\n", buf); /* prefix */
routes_displayed++;

View File

@ -1146,7 +1146,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
char buf_age[BUFSIZ];
if (bi && bi->extra && bi->extra->vnc.import.create_time) {
if (bi->extra && bi->extra->vnc.import.create_time) {
rfapiFormatAge(bi->extra->vnc.import.create_time,
buf_age, BUFSIZ);
} else {
@ -1163,7 +1163,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
* print that on the next line
*/
if (bi && bi->extra
if (bi->extra
&& bi->extra->vnc.import.aux_prefix.family) {
const char *sp;
@ -1527,11 +1527,9 @@ void rfapiPrintRfapiIpPrefix(void *stream, struct rfapi_ip_prefix *p)
void rfapiPrintRd(struct vty *vty, struct prefix_rd *prd)
{
char buf[BUFSIZ];
char buf[RD_ADDRSTRLEN];
buf[0] = 0;
prefix_rd2str(prd, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix_rd2str(prd, buf, sizeof(buf));
vty_out(vty, "%s", buf);
}
@ -1599,7 +1597,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
int rc;
afi_t afi;
struct rfapi_adb *adb;
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
vty_out(vty, "%-10p ", rfd);
rfapiPrintRfapiIpAddr(vty, &rfd->un_addr);
@ -1651,8 +1649,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
if (family != adb->u.s.prefix_ip.family)
continue;
prefix2str(&adb->u.s.prefix_ip, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix2str(&adb->u.s.prefix_ip, buf, sizeof(buf));
vty_out(vty, " Adv Pfx: %s%s", buf, HVTYNL);
rfapiPrintAdvertisedInfo(vty, rfd, SAFI_MPLS_VPN,
@ -1664,8 +1661,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
rc == 0; rc = skiplist_next(rfd->advertised.ip0_by_ether, NULL,
(void **)&adb, &cursor)) {
prefix2str(&adb->u.s.prefix_eth, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
prefix2str(&adb->u.s.prefix_eth, buf, sizeof(buf));
vty_out(vty, " Adv Pfx: %s%s", buf, HVTYNL);

View File

@ -437,14 +437,11 @@ static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
continue;
{
char prefixstr[BUFSIZ];
char prefixstr[PREFIX_STRLEN];
prefixstr[0] = 0;
inet_ntop(rn->p.family, &rn->p.u.prefix, prefixstr,
BUFSIZ);
vnc_zlog_debug_verbose("%s: checking prefix %s/%d",
__func__, prefixstr,
rn->p.prefixlen);
prefix2str(&rn->p, prefixstr, sizeof(prefixstr));
vnc_zlog_debug_verbose("%s: checking prefix %s",
__func__, prefixstr);
}
for (ri = rn->info; ri; ri = ri->next) {
@ -1856,14 +1853,13 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
continue;
{
char prefixstr[BUFSIZ];
char prefixstr[PREFIX_STRLEN];
prefixstr[0] = 0;
inet_ntop(rn->p.family, &rn->p.u.prefix,
prefixstr, BUFSIZ);
prefix2str(&rn->p, prefixstr,
sizeof(prefixstr));
vnc_zlog_debug_verbose(
"%s: checking prefix %s/%d", __func__,
prefixstr, rn->p.prefixlen);
"%s: checking prefix %s", __func__,
prefixstr);
}
/*

View File

@ -205,15 +205,15 @@ static void print_rhn_list(const char *tag1, const char *tag2)
/* XXX uses secret knowledge of skiplist structure */
for (p = sl->header->forward[0]; p; p = p->forward[0]) {
char kbuf[BUFSIZ];
char hbuf[BUFSIZ];
char ubuf[BUFSIZ];
char kbuf[PREFIX_STRLEN];
char hbuf[PREFIX_STRLEN];
char ubuf[PREFIX_STRLEN];
pb = p->value;
prefix2str(p->key, kbuf, BUFSIZ);
prefix2str(&pb->hpfx, hbuf, BUFSIZ);
prefix2str(&pb->upfx, ubuf, BUFSIZ);
prefix2str(p->key, kbuf, sizeof(kbuf));
prefix2str(&pb->hpfx, hbuf, sizeof(hbuf));
prefix2str(&pb->upfx, ubuf, sizeof(ubuf));
vnc_zlog_debug_verbose(
"RHN Entry %d (q=%p): kpfx=%s, upfx=%s, hpfx=%s, ubi=%p",
@ -259,14 +259,11 @@ static void vnc_rhnck(char *tag)
* pfx */
assert(!vnc_prefix_cmp(&pb->hpfx, pkey));
if (vnc_prefix_cmp(&pb->hpfx, &pfx_orig_nexthop)) {
char str_onh[BUFSIZ];
char str_nve_pfx[BUFSIZ];
char str_onh[PREFIX_STRLEN];
char str_nve_pfx[PREFIX_STRLEN];
prefix2str(&pfx_orig_nexthop, str_onh, BUFSIZ);
str_onh[BUFSIZ - 1] = 0;
prefix2str(&pb->hpfx, str_nve_pfx, BUFSIZ);
str_nve_pfx[BUFSIZ - 1] = 0;
prefix2str(&pfx_orig_nexthop, str_onh, sizeof(str_onh));
prefix2str(&pb->hpfx, str_nve_pfx, sizeof(str_nve_pfx));
vnc_zlog_debug_verbose(
"%s: %s: FATAL: resolve_nve_nexthop list item bi nexthop %s != nve pfx %s",
@ -529,10 +526,9 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_rd(
return;
{
char str_nh[BUFSIZ];
char str_nh[PREFIX_STRLEN];
prefix2str(ubi_nexthop, str_nh, BUFSIZ);
str_nh[BUFSIZ - 1] = 0;
prefix2str(ubi_nexthop, str_nh, sizeof(str_nh));
vnc_zlog_debug_verbose("%s: ubi_nexthop=%s", __func__, str_nh);
}
@ -574,18 +570,16 @@ static void vnc_import_bgp_add_route_mode_resolve_nve(
/*debugging */
if (VNC_DEBUG(VERBOSE)) {
char str_pfx[BUFSIZ];
char str_nh[BUFSIZ];
char str_pfx[PREFIX_STRLEN];
char str_nh[PREFIX_STRLEN];
struct prefix nh;
prefix2str(prefix, str_pfx, BUFSIZ);
str_pfx[BUFSIZ - 1] = 0;
prefix2str(prefix, str_pfx, sizeof(str_pfx));
nh.prefixlen = 0;
rfapiUnicastNexthop2Prefix(afi, info->attr, &nh);
if (nh.prefixlen) {
prefix2str(&nh, str_nh, BUFSIZ);
str_nh[BUFSIZ - 1] = 0;
prefix2str(&nh, str_nh, sizeof(str_nh));
} else {
str_nh[0] = '?';
str_nh[1] = 0;
@ -718,11 +712,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
uint32_t *med = NULL;
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
buf[0] = 0;
prefix2str(prefix, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s(prefix=%s) entry", __func__, buf);
}
@ -789,11 +781,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
}
if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
buf[0] = 0;
prefix2str(vn_pfx, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(vn_pfx, buf, sizeof(buf));
vnc_zlog_debug_any("%s vn_pfx=%s", __func__, buf);
}
@ -867,11 +857,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
}
if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
buf[0] = 0;
rfapiRfapiIpAddr2Str(&vnaddr, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
rfapiRfapiIpAddr2Str(&vnaddr, buf, sizeof(buf));
vnc_zlog_debug_any("%s: setting vnaddr to %s", __func__, buf);
}
@ -910,11 +898,9 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
uint32_t local_pref;
{
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
buf[0] = 0;
prefix2str(prefix, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose("%s(prefix=%s) entry", __func__, buf);
}
@ -997,11 +983,9 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
}
if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
buf[0] = 0;
prefix2str(vn_pfx, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
prefix2str(vn_pfx, buf, sizeof(buf));
vnc_zlog_debug_any("%s vn_pfx=%s", __func__, buf);
}
@ -1183,7 +1167,8 @@ static void vnc_import_bgp_del_route_mode_nvegroup(struct bgp *bgp,
assert(afi);
assert((rfg = bgp->rfapi_cfg->rfg_redist));
rfg = bgp->rfapi_cfg->rfg_redist;
assert(rfg);
/*
* Compute VN address
@ -1297,11 +1282,9 @@ static void vnc_import_bgp_del_route_mode_resolve_nve_one_rd(
return;
{
char str_nh[BUFSIZ];
prefix2str(ubi_nexthop, str_nh, BUFSIZ);
str_nh[BUFSIZ - 1] = 0;
char str_nh[PREFIX_STRLEN];
prefix2str(ubi_nexthop, str_nh, sizeof(str_nh));
vnc_zlog_debug_verbose("%s: ubi_nexthop=%s", __func__, str_nh);
}
@ -1450,7 +1433,7 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
return;
}
if (bgp && bgp->rfapi)
if (bgp->rfapi)
sl = bgp->rfapi->resolve_nve_nexthop;
if (!sl) {
@ -1477,11 +1460,11 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
sizeof(struct prefix)); /* keep valgrind happy */
if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
char hbuf[BUFSIZ];
char ubuf[BUFSIZ];
char hbuf[PREFIX_STRLEN];
char ubuf[PREFIX_STRLEN];
prefix2str(&pb->hpfx, hbuf, BUFSIZ);
prefix2str(&pb->upfx, ubuf, BUFSIZ);
prefix2str(&pb->hpfx, hbuf, sizeof(hbuf));
prefix2str(&pb->upfx, ubuf, sizeof(ubuf));
vnc_zlog_debug_any(
"%s: examining RHN Entry (q=%p): upfx=%s, hpfx=%s, ubi=%p",
@ -1509,14 +1492,12 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
* Sanity check
*/
if (vnc_prefix_cmp(&pfx_unicast_nexthop, prefix)) {
char str_unh[BUFSIZ];
char str_nve_pfx[BUFSIZ];
char str_unh[PREFIX_STRLEN];
char str_nve_pfx[PREFIX_STRLEN];
prefix2str(&pfx_unicast_nexthop, str_unh, BUFSIZ);
str_unh[BUFSIZ - 1] = 0;
prefix2str(prefix, str_nve_pfx, BUFSIZ);
str_nve_pfx[BUFSIZ - 1] = 0;
prefix2str(&pfx_unicast_nexthop, str_unh,
sizeof(str_unh));
prefix2str(prefix, str_nve_pfx, sizeof(str_nve_pfx));
vnc_zlog_debug_verbose(
"%s: FATAL: resolve_nve_nexthop list item bi nexthop %s != nve pfx %s",
@ -1535,9 +1516,9 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
#if DEBUG_RHN_LIST
/* debug */
{
char pbuf[BUFSIZ];
char pbuf[PREFIX_STRLEN];
prefix2str(prefix, pbuf, BUFSIZ);
prefix2str(prefix, pbuf, sizeof(pbuf));
vnc_zlog_debug_verbose(
"%s: advancing past RHN Entry (q=%p): with prefix %s",
@ -1565,10 +1546,9 @@ void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
int rc;
{
char str_pfx[BUFSIZ];
char str_pfx[PREFIX_STRLEN];
prefix2str(prefix, str_pfx, BUFSIZ);
str_pfx[BUFSIZ - 1] = 0;
prefix2str(prefix, str_pfx, sizeof(str_pfx));
vnc_zlog_debug_verbose("%s(bgp=%p, nve prefix=%s)", __func__,
bgp, str_pfx);
@ -1597,7 +1577,7 @@ void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
return;
}
if (bgp && bgp->rfapi)
if (bgp->rfapi)
sl = bgp->rfapi->resolve_nve_nexthop;
if (!sl) {
@ -1636,14 +1616,12 @@ void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
* Sanity check
*/
if (vnc_prefix_cmp(&pfx_unicast_nexthop, prefix)) {
char str_unh[BUFSIZ];
char str_nve_pfx[BUFSIZ];
char str_unh[PREFIX_STRLEN];
char str_nve_pfx[PREFIX_STRLEN];
prefix2str(&pfx_unicast_nexthop, str_unh, BUFSIZ);
str_unh[BUFSIZ - 1] = 0;
prefix2str(prefix, str_nve_pfx, BUFSIZ);
str_nve_pfx[BUFSIZ - 1] = 0;
prefix2str(&pfx_unicast_nexthop, str_unh,
sizeof(str_unh));
prefix2str(prefix, str_nve_pfx, sizeof(str_nve_pfx));
vnc_zlog_debug_verbose(
"%s: FATAL: resolve_nve_nexthop list item bi nexthop %s != nve pfx %s",
@ -2092,11 +2070,9 @@ void vnc_import_bgp_exterior_add_route_interior(
/*debugging */
{
char str_pfx[BUFSIZ];
prefix2str(&rn_interior->p, str_pfx, BUFSIZ);
str_pfx[BUFSIZ - 1] = 0;
char str_pfx[PREFIX_STRLEN];
prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx));
vnc_zlog_debug_verbose("%s: interior prefix=%s, bi type=%d",
__func__, str_pfx, bi_interior->type);
}
@ -2337,11 +2313,10 @@ void vnc_import_bgp_exterior_add_route_interior(
(void **)&pfx_exterior, &cursor)) {
struct prefix pfx_nexthop;
char buf[BUFSIZ];
char buf[PREFIX_STRLEN];
afi_t afi_exterior = family2afi(pfx_exterior->family);
prefix2str(pfx_exterior, buf, sizeof(buf));
buf[sizeof(buf) - 1] = 0;
vnc_zlog_debug_verbose(
"%s: checking exterior orphan at prefix %s", __func__,
buf);
@ -2480,10 +2455,9 @@ void vnc_import_bgp_exterior_del_route_interior(
/*debugging */
{
char str_pfx[BUFSIZ];
char str_pfx[PREFIX_STRLEN];
prefix2str(&rn_interior->p, str_pfx, BUFSIZ);
str_pfx[BUFSIZ - 1] = 0;
prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx));
vnc_zlog_debug_verbose("%s: interior prefix=%s, bi type=%d",
__func__, str_pfx, bi_interior->type);
@ -2639,12 +2613,12 @@ void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix,
if (VNC_DEBUG(VERBOSE)) {
struct prefix pfx_nexthop;
char buf[BUFSIZ];
char buf_nh[BUFSIZ];
char buf[PREFIX_STRLEN];
char buf_nh[PREFIX_STRLEN];
prefix2str(prefix, buf, BUFSIZ);
prefix2str(prefix, buf, sizeof(buf));
rfapiUnicastNexthop2Prefix(afi, info->attr, &pfx_nexthop);
prefix2str(&pfx_nexthop, buf_nh, BUFSIZ);
prefix2str(&pfx_nexthop, buf_nh, sizeof(buf_nh));
vnc_zlog_debug_verbose("%s: pfx %s, nh %s", __func__, buf,
buf_nh);
@ -2709,12 +2683,12 @@ void vnc_import_bgp_del_route(struct bgp *bgp, struct prefix *prefix,
{
struct prefix pfx_nexthop;
char buf[BUFSIZ];
char buf_nh[BUFSIZ];
char buf[PREFIX_STRLEN];
char buf_nh[PREFIX_STRLEN];
prefix2str(prefix, buf, BUFSIZ);
prefix2str(prefix, buf, sizeof(buf));
rfapiUnicastNexthop2Prefix(afi, info->attr, &pfx_nexthop);
prefix2str(&pfx_nexthop, buf_nh, BUFSIZ);
prefix2str(&pfx_nexthop, buf_nh, sizeof(buf_nh));
vnc_zlog_debug_verbose("%s: pfx %s, nh %s", __func__, buf,
buf_nh);

View File

@ -30,6 +30,7 @@
#include "lib/command.h"
#include "lib/zclient.h"
#include "lib/stream.h"
#include "lib/ringbuf.h"
#include "lib/memory.h"
#include "bgpd/bgpd.h"
@ -198,7 +199,7 @@ static void vnc_redistribute_add(struct prefix *p, u_int32_t metric,
stream_fifo_free(vncHD1VR.peer->obuf);
if (vncHD1VR.peer->ibuf_work)
stream_free(vncHD1VR.peer->ibuf_work);
ringbuf_del(vncHD1VR.peer->ibuf_work);
if (vncHD1VR.peer->obuf_work)
stream_free(vncHD1VR.peer->obuf_work);
@ -384,6 +385,8 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
struct zapi_route api;
struct zapi_nexthop *api_nh;
int i;
struct in_addr **nhp_ary4 = nhp_ary;
struct in6_addr **nhp_ary6 = nhp_ary;
if (!nhp_count) {
vnc_zlog_debug_verbose("%s: empty nexthop list, skipping",
@ -393,6 +396,7 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.nh_vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_VNC;
api.safi = SAFI_UNICAST;
api.prefix = *p;
@ -401,20 +405,16 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = MIN(nhp_count, multipath_num);
for (i = 0; i < api.nexthop_num; i++) {
struct in_addr *nhp_ary4;
struct in6_addr *nhp_ary6;
api_nh = &api.nexthops[i];
switch (p->family) {
case AF_INET:
nhp_ary4 = nhp_ary;
memcpy(&api_nh->gate.ipv4, &nhp_ary4[i],
memcpy(&api_nh->gate.ipv4, nhp_ary4[i],
sizeof(api_nh->gate.ipv4));
api_nh->type = NEXTHOP_TYPE_IPV4;
break;
case AF_INET6:
nhp_ary6 = nhp_ary;
memcpy(&api_nh->gate.ipv6, &nhp_ary6[i],
memcpy(&api_nh->gate.ipv6, nhp_ary6[i],
sizeof(api_nh->gate.ipv6));
api_nh->type = NEXTHOP_TYPE_IPV6;
break;

View File

@ -40,7 +40,7 @@ AS_IF([test "$host" != "$build"], [
( CPPFLAGS="$HOST_CPPFLAGS"; \
CFLAGS="$HOST_CFLAGS"; \
LDFLAGS="$HOST_LDFLAGS"; \
cd hosttools; "${abssrc}/configure" "--host=$build" "--build=$build"; )
cd hosttools; "${abssrc}/configure" "--host=$build" "--build=$build" "--enable-clippy-only" "--disable-nhrpd" "--disable-vtysh"; )
AC_MSG_NOTICE([...])
AC_MSG_NOTICE([... cross-compilation: finished self-configuring for build platform tools])
@ -354,6 +354,8 @@ AC_ARG_ENABLE(logfile_mask,
AS_HELP_STRING([--enable-logfile-mask=ARG], [set mask for log files]))
AC_ARG_ENABLE(shell_access,
AS_HELP_STRING([--enable-shell-access], [Allow users to access shell/telnet/ssh]))
AC_ARG_ENABLE(realms,
AS_HELP_STRING([--enable-realms], [enable REALMS support under Linux]))
AC_ARG_ENABLE(rtadv,
AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature]))
AC_ARG_ENABLE(irdp,
@ -392,7 +394,10 @@ AC_ARG_ENABLE([oldvpn_commands],
AS_HELP_STRING([--enable-oldvpn-commands], [Keep old vpn commands]))
AC_ARG_ENABLE(rpki,
AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
AC_ARG_ENABLE([clippy-only],
AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
AS_IF([test "${enable_clippy_only}" != "yes"], [
AC_CHECK_HEADERS(json-c/json.h)
AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c", [], [-lm])
if test $ac_cv_lib_json_c_json_object_get = no; then
@ -401,6 +406,7 @@ if test $ac_cv_lib_json_c_json_object_get = no; then
AC_MSG_ERROR([lib json is needed to compile])
fi
fi
])
AC_ARG_ENABLE([dev_build],
AS_HELP_STRING([--enable-dev-build], [build for development]))
@ -875,6 +881,7 @@ case "$host_os" in
AC_DEFINE(OPEN_BSD,,OpenBSD)
AC_DEFINE(KAME,1,KAME IPv6)
AC_DEFINE(BSD_V6_SYSCTL,1,BSD v6 sysctl to turn on and off forwarding)
if test "x${enable_pimd}" != "xno"; then
case "$host_os" in
@ -891,12 +898,29 @@ case "$host_os" in
AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST)
AC_DEFINE(KAME,1,KAME IPv6)
AC_DEFINE(BSD_V6_SYSCTL,1,BSD v6 sysctl to turn on and off forwarding)
;;
esac
AM_CONDITIONAL(SOLARIS, test "${SOLARIS}" = "solaris")
AC_SYS_LARGEFILE
dnl ------------------------
dnl Integrated REALMS option
dnl ------------------------
if test "${enable_realms}" = "yes"; then
case "$host_os" in
linux*)
AC_DEFINE(SUPPORT_REALMS,, Realms support)
;;
*)
echo "Sorry, only Linux has REALMS support"
exit 1
;;
esac
fi
AM_CONDITIONAL([SUPPORT_REALMS], [test "${enable_realms}" = "yes"])
dnl ---------------------
dnl Integrated VTY option
dnl ---------------------

View File

@ -35,6 +35,7 @@ EXTRA_DIST = README.Debian README.Maintainer \
backports/ubuntu17.10/versionext \
frr-doc.docs frr-doc.info frr-doc.install \
frr-doc.lintian-overrides frr.conf \
frr-dbg.lintian-overrides \
frr.dirs frr.docs frr.install \
frr.lintian-overrides frr.logrotate \
frr.manpages frr.pam frr.postinst frr.postrm \

View File

@ -72,7 +72,7 @@ adding a new backport.
(see `rules` file for available options)
export WANT_BGP_VNC=1
export WANT_WANT_CUMULUS_MODE=1
export WANT_CUMULUS_MODE=1
debuild -b -uc -us
DONE.

View File

@ -59,17 +59,37 @@ $(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi
frr.dvi: $(frr_TEXINFOS) defines.texi
frr.html: $(frr_TEXINFOS) defines.texi
frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \
frr_TEXINFOS = \
appendix.texi \
basic.texi \
bgpd.texi \
isisd.texi \
filter.texi \
vnc.texi \
babeld.texi \
install.texi ipv6.texi kernel.texi main.texi \
install.texi \
ipv6.texi \
kernel.texi \
main.texi \
nhrpd.texi \
eigrpd.texi \
ospf6d.texi ospfd.texi \
overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \
snmp.texi vtysh.texi routeserver.texi $(figures_png) \
snmptrap.texi ospf_fundamentals.texi isisd.texi $(figures_txt) \
rpki.texi
ospf6d.texi \
ospfd.texi \
overview.texi \
protocol.texi \
ripd.texi \
ripngd.texi \
routemap.texi \
snmp.texi \
vtysh.texi \
routeserver.texi \
$(figures_png) \
snmptrap.texi \
ospf_fundamentals.texi \
isisd.texi $(figures_txt) \
rpki.texi \
pimd.texi \
#END
.png.eps:
$(PNGTOEPS) $< "$@"

2142
doc/bgpd.texi Normal file

File diff suppressed because it is too large Load Diff

291
doc/install.texi Normal file
View File

@ -0,0 +1,291 @@
@node Installation
@chapter Installation
@cindex How to install Frr
@cindex Installation
@cindex Installing Frr
@cindex Building the system
@cindex Making Frr
There are three steps for installing the software: configuration,
compilation, and installation.
@menu
* Configure the Software::
* Build the Software::
* Install the Software::
@end menu
The easiest way to get Frr running is to issue the following
commands:
@example
% configure
% make
% make install
@end example
@node Configure the Software
@section Configure the Software
@menu
* The Configure script and its options::
* Least-Privilege support::
* Linux notes::
@end menu
@node The Configure script and its options
@subsection The Configure script and its options
@cindex Configuration options
@cindex Options for configuring
@cindex Build options
@cindex Distribution configuration
@cindex Options to @code{./configure}
Frr has an excellent configure script which automatically detects most
host configurations. There are several additional configure options to
customize the build to include or exclude specific features and dependencies.
@table @option
@item --disable-zebra
Do not build zebra daemon.
@item --disable-ripd
Do not build ripd.
@item --disable-ripngd
Do not build ripngd.
@item --disable-ospfd
Do not build ospfd.
@item --disable-ospf6d
Do not build ospf6d.
@item --disable-bgpd
Do not build bgpd.
@item --disable-bgp-announce
Make @command{bgpd} which does not make bgp announcements at all. This
feature is good for using @command{bgpd} as a BGP announcement listener.
@item --enable-datacenter
Enable system defaults to work as if in a Data Center. See defaults.h
for what is changed by this configure option.
@item --enable-snmp
Enable SNMP support. By default, SNMP support is disabled.
@item --disable-ospfapi
Disable support for OSPF-API, an API to interface directly with ospfd.
OSPF-API is enabled if --enable-opaque-lsa is set.
@item --disable-ospfclient
Disable building of the example OSPF-API client.
@item --disable-ospf-ri
Disable support for OSPF Router Information (RFC4970 & RFC5088) this
requires support for Opaque LSAs and Traffic Engineering.
@item --disable-isisd
Do not build isisd.
@item --enable-isis-topology
Enable IS-IS topology generator.
@item --enable-isis-te
Enable Traffic Engineering Extension for ISIS (RFC5305)
@item --enable-multipath=@var{ARG}
Enable support for Equal Cost Multipath. @var{ARG} is the maximum number
of ECMP paths to allow, set to 0 to allow unlimited number of paths.
@item --enable-realms
Enable the support of linux Realms. Convert tag values from 1-255
into a realm value when inserting into the linux kernel. Then
routing policy can be assigned to the realm. See the tc man page.
@item --disable-rtadv
Disable support IPV6 router advertisement in zebra.
@item --enable-gcc-rdynamic
Pass the @command{-rdynamic} option to the linker driver. This is in most
cases neccessary for getting usable backtraces. This option defaults to on
if the compiler is detected as gcc, but giving an explicit enable/disable is
suggested.
@item --disable-backtrace
Controls backtrace support for the crash handlers. This is autodetected by
default. Using the switch will enforce the requested behaviour, failing with
an error if support is requested but not available. On BSD systems, this
needs libexecinfo, while on glibc support for this is part of libc itself.
@item --enable-dev-build
Turn on some options for compiling FRR within a development environment in
mind. Specifically turn on -g3 -O0 for compiling options and add inclusion
of grammar sandbox.
@item --enable-fuzzing
Turn on some compile options to allow you to run fuzzing tools
against the system. This tools is intended as a developer
only tool and should not be used for normal operations
@end table
You may specify any combination of the above options to the configure
script. By default, the executables are placed in @file{/usr/local/sbin}
and the configuration files in @file{/usr/local/etc}. The @file{/usr/local/}
installation prefix and other directories may be changed using the following
options to the configuration script.
@table @option
@item --prefix=@var{prefix}
Install architecture-independent files in @var{prefix} [/usr/local].
@item --sysconfdir=@var{dir}
Look for configuration files in @var{dir} [@var{prefix}/etc]. Note
that sample configuration files will be installed here.
@item --localstatedir=@var{dir}
Configure zebra to use @var{dir} for local state files, such
as pid files and unix sockets.
@end table
@example
% ./configure --disable-snmp
@end example
This command will configure zebra and the routing daemons.
@node Least-Privilege support
@subsection Least-Privilege support
@cindex Frr Least-Privileges
@cindex Frr Privileges
Additionally, you may configure zebra to drop its elevated privileges
shortly after startup and switch to another user. The configure script will
automatically try to configure this support. There are three configure
options to control the behaviour of Frr daemons.
@table @option
@item --enable-user=@var{user}
Switch to user @var{ARG} shortly after startup, and run as user @var{ARG}
in normal operation.
@item --enable-group=@var{group}
Switch real and effective group to @var{group} shortly after
startup.
@item --enable-vty-group=@var{group}
Create Unix Vty sockets (for use with vtysh) with group owndership set to
@var{group}. This allows one to create a seperate group which is
restricted to accessing only the Vty sockets, hence allowing one to
delegate this group to individual users, or to run vtysh setgid to
this group.
@end table
The default user and group which will be configured is 'frr' if no user
or group is specified. Note that this user or group requires write access to
the local state directory (see --localstatedir) and requires at least read
access, and write access if you wish to allow daemons to write out their
configuration, to the configuration directory (see --sysconfdir).
On systems which have the 'libcap' capabilities manipulation library
(currently only linux), the frr system will retain only minimal
capabilities required, further it will only raise these capabilities for
brief periods. On systems without libcap, frr will run as the user
specified and only raise its uid back to uid 0 for brief periods.
@node Linux notes
@subsection Linux Notes
@cindex Configuring Frr
@cindex Building on Linux boxes
@cindex Linux configurations
There are several options available only to @sc{gnu}/Linux systems:
@footnote{@sc{gnu}/Linux has very flexible kernel configuration features}. If
you use @sc{gnu}/Linux, make sure that the current kernel configuration is
what you want. Frr will run with any kernel configuration but some
recommendations do exist.
@table @var
@item CONFIG_NETLINK
Kernel/User netlink socket. This is a brand new feature which enables an
advanced interface between the Linux kernel and zebra (@pxref{Kernel Interface}).
@item CONFIG_RTNETLINK
Routing messages.
This makes it possible to receive netlink routing messages. If you
specify this option, @command{zebra} can detect routing information
updates directly from the kernel (@pxref{Kernel Interface}).
@item CONFIG_IP_MULTICAST
IP: multicasting.
This option should be specified when you use @command{ripd} (@pxref{RIP}) or
@command{ospfd} (@pxref{OSPFv2}) because these protocols use multicast.
@end table
IPv6 support has been added in @sc{gnu}/Linux kernel version 2.2. If you
try to use the Frr IPv6 feature on a @sc{gnu}/Linux kernel, please
make sure the following libraries have been installed. Please note that
these libraries will not be needed when you uses @sc{gnu} C library 2.1
or upper.
@table @code
@item inet6-apps
The @code{inet6-apps} package includes basic IPv6 related libraries such
as @code{inet_ntop} and @code{inet_pton}. Some basic IPv6 programs such
as @command{ping}, @command{ftp}, and @command{inetd} are also
included. The @code{inet-apps} can be found at
@uref{ftp://ftp.inner.net/pub/ipv6/}.
@item net-tools
The @code{net-tools} package provides an IPv6 enabled interface and
routing utility. It contains @command{ifconfig}, @command{route},
@command{netstat}, and other tools. @code{net-tools} may be found at
@uref{http://www.tazenda.demon.co.uk/phil/net-tools/}.
@end table
@c A - end of footnote
@node Build the Software
@section Build the Software
After configuring the software, you will need to compile it for your
system. Simply issue the command @command{make} in the root of the source
directory and the software will be compiled. Cliff Note versions of
different compilation examples can be found in the doc/Building_FRR_on_XXX.md
files. If you have *any* problems at this stage, be certain to send a
bug report @xref{Bug Reports}.
@example
% ./bootstrap.sh
% ./configure <appropriate to your system>
% make
@end example
@c A - End of node, Building the Software
@node Install the Software
@comment node-name, next, previous, up
@section Install the Software
Installing the software to your system consists of copying the compiled
programs and supporting files to a standard location. After the
installation process has completed, these files have been copied
from your work directory to @file{/usr/local/bin}, and @file{/usr/local/etc}.
To install the Frr suite, issue the following command at your shell
prompt: @command{make install}.
@example
%
% make install
%
@end example
Frr daemons have their own terminal interface or VTY. After
installation, you have to setup each beast's port number to connect to
them. Please add the following entries to @file{/etc/services}.
@example
zebrasrv 2600/tcp # zebra service
zebra 2601/tcp # zebra vty
ripd 2602/tcp # RIPd vty
ripngd 2603/tcp # RIPngd vty
ospfd 2604/tcp # OSPFd vty
bgpd 2605/tcp # BGPd vty
ospf6d 2606/tcp # OSPF6d vty
ospfapi 2607/tcp # ospfapi
isisd 2608/tcp # ISISd vty
nhrpd 2610/tcp # nhrpd vty
pimd 2611/tcp # PIMd vty
@end example
If you use a FreeBSD newer than 2.2.8, the above entries are already
added to @file{/etc/services} so there is no need to add it. If you
specify a port number when starting the daemon, these entries may not be
needed.
You may need to make changes to the config files in
@file{@value{INSTALL_PREFIX_ETC}/*.conf}. @xref{Config Commands}.

433
doc/isisd.texi Normal file
View File

@ -0,0 +1,433 @@
@cindex ISIS
@node ISIS
@chapter ISIS
@acronym{ISIS,Intermediate System to Intermediate System} is a routing protocol
which is described in @cite{ISO10589, RFC1195, RFC5308}. ISIS is an
@acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP},
@acronym{ISIS} can provide scalable network support and faster
convergence times like @acronym{OSPF}. ISIS is widely used in large networks such as
@acronym{ISP,Internet Service Provider} and carrier backbone networks.
@menu
* Configuring isisd::
* ISIS router::
* ISIS Timer::
* ISIS region::
* ISIS interface::
* Showing ISIS information::
* ISIS Traffic Engineering::
* Debugging ISIS::
* ISIS Configuration Examples::
@end menu
@node Configuring isisd
@section Configuring isisd
There are no @command{isisd} specific options. Common options can be
specified (@pxref{Common Invocation Options}) to @command{isisd}.
@command{isisd} needs to acquire interface information from
@command{zebra} in order to function. Therefore @command{zebra} must be
running before invoking @command{isisd}. Also, if @command{zebra} is
restarted then @command{isisd} must be too.
Like other daemons, @command{isisd} configuration is done in @acronym{ISIS}
specific configuration file @file{isisd.conf}.
@node ISIS router
@section ISIS router
To start ISIS process you have to specify the ISIS router. As of this
writing, @command{isisd} does not support multiple ISIS processes.
@deffn Command {router isis WORD} {}
@deffnx Command {no router isis WORD} {}
@anchor{router isis WORD}Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'.
@command{isisd} does not yet support multiple ISIS processes but you must specify
the name of ISIS process. The ISIS process name 'WORD' is then used for interface
(see command @ref{ip router isis WORD}).
@end deffn
@deffn {ISIS Command} {net XX.XXXX. ... .XXX.XX} {}
@deffnx {ISIS Command} {no net XX.XXXX. ... .XXX.XX} {}
Set/Unset network entity title (NET) provided in ISO format.
@end deffn
@deffn {ISIS Command} {hostname dynamic} {}
@deffnx {ISIS Command} {no hostname dynamic} {}
Enable support for dynamic hostname.
@end deffn
@deffn {ISIS Command} {area-password [clear | md5] <password>} {}
@deffnx {ISIS Command} {domain-password [clear | md5] <password>} {}
@deffnx {ISIS Command} {no area-password} {}
@deffnx {ISIS Command} {no domain-password} {}
Configure the authentication password for an area, respectively a domain,
as clear text or md5 one.
@end deffn
@deffn {ISIS Command} {log-adjacency-changes} {}
@deffnx {ISIS Command} {no log-adjacency-changes} {}
Log changes in adjacency state.
@end deffn
@deffn {ISIS Command} {metric-style [narrow | transition | wide]} {}
@deffnx {ISIS Command} {no metric-style} {}
@anchor{metric-style}Set old-style (ISO 10589) or new-style packet formats:
- narrow Use old style of TLVs with narrow metric
- transition Send and accept both styles of TLVs during transition
- wide Use new style of TLVs to carry wider metric
@end deffn
@deffn {ISIS Command} {set-overload-bit} {}
@deffnx {ISIS Command} {no set-overload-bit} {}
Set overload bit to avoid any transit traffic.
@end deffn
@node ISIS Timer
@section ISIS Timer
@deffn {ISIS Command} {lsp-gen-interval <1-120>} {}
@deffnx {ISIS Command} {lsp-gen-interval [level-1 | level-2] <1-120>} {}
@deffnx {ISIS Command} {no lsp-gen-interval} {}
@deffnx {ISIS Command} {no lsp-gen-interval [level-1 | level-2]} {}
Set minimum interval in seconds between regenerating same LSP,
globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {}
@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {}
@deffnx {ISIS Command} {no lsp-refresh-interval} {}
@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {}
Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {}
@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {}
@deffnx {ISIS Command} {no lsp-refresh-interval} {}
@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {}
Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {ISIS Command} {max-lsp-lifetime <360-65535>} {}
@deffnx {ISIS Command} {max-lsp-lifetime [level-1 | level-2] <360-65535>} {}
@deffnx {ISIS Command} {no max-lsp-lifetime} {}
@deffnx {ISIS Command} {no max-lsp-lifetime [level-1 | level-2]} {}
Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {ISIS Command} {spf-interval <1-120>} {}
@deffnx {ISIS Command} {spf-interval [level-1 | level-2] <1-120>} {}
@deffnx {ISIS Command} {no spf-interval} {}
@deffnx {ISIS Command} {no spf-interval [level-1 | level-2]} {}
Set minimum interval between consecutive SPF calculations in seconds.
@end deffn
@node ISIS region
@section ISIS region
@deffn {ISIS Command} {is-type [level-1 | level-1-2 | level-2-only]} {}
@deffnx {ISIS Command} {no is-type} {}
Define the ISIS router behavior:
- level-1 Act as a station router only
- level-1-2 Act as both a station router and an area router
- level-2-only Act as an area router only
@end deffn
@node ISIS interface
@section ISIS interface
@deffn {Interface Command} {ip router isis WORD} {}
@deffnx {Interface Command} {no ip router isis WORD} {}
@anchor{ip router isis WORD}Activate ISIS adjacency on this interface. Note that the name
of ISIS instance must be the same as the one used to configure the ISIS process
(see command @ref{router isis WORD}).
@end deffn
@deffn {Interface Command} {isis circuit-type [level-1 | level-1-2 | level-2]} {}
@deffnx {Interface Command} {no isis circuit-type} {}
Configure circuit type for interface:
- level-1 Level-1 only adjacencies are formed
- level-1-2 Level-1-2 adjacencies are formed
- level-2-only Level-2 only adjacencies are formed
@end deffn
@deffn {Interface Command} {isis csnp-interval <1-600>} {}
@deffnx {Interface Command} {isis csnp-interval <1-600> [level-1 | level-2]} {}
@deffnx {Interface Command} {no isis csnp-interval} {}
@deffnx {Interface Command} {no isis csnp-interval [level-1 | level-2]} {}
Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {Interface Command} {isis hello padding} {}
Add padding to IS-IS hello packets.
@end deffn
@deffn {Interface Command} {isis hello-interval <1-600>} {}
@deffnx {Interface Command} {isis hello-interval <1-600> [level-1 | level-2]} {}
@deffnx {Interface Command} {no isis hello-interval} {}
@deffnx {Interface Command} {no isis hello-interval [level-1 | level-2]} {}
Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {Interface Command} {isis hello-multiplier <2-100>} {}
@deffnx {Interface Command} {isis hello-multiplier <2-100> [level-1 | level-2]} {}
@deffnx {Interface Command} {no isis hello-multiplier} {}
@deffnx {Interface Command} {no isis hello-multiplier [level-1 | level-2]} {}
Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2).
@end deffn
@deffn {Interface Command} {isis metric [<0-255> | <0-16777215>]} {}
@deffnx {Interface Command} {isis metric [<0-255> | <0-16777215>] [level-1 | level-2]} {}
@deffnx {Interface Command} {no isis metric} {}
@deffnx {Interface Command} {no isis metric [level-1 | level-2]} {}
Set default metric value globally, for an area (level-1) or a domain (level-2).
Max value depend if metric support narrow or wide value (see command @ref{metric-style}).
@end deffn
@deffn {Interface Command} {isis network point-to-point} {}
@deffnx {Interface Command} {no isis network point-to-point} {}
Set network type to 'Point-to-Point' (broadcast by default).
@end deffn
@deffn {Interface Command} {isis passive} {}
@deffnx {Interface Command} {no isis passive} {}
Configure the passive mode for this interface.
@end deffn
@deffn {Interface Command} {isis password [clear | md5] <password>} {}
@deffnx {Interface Command} {no isis password} {}
Configure the authentication password (clear or encoded text) for the interface.
@end deffn
@deffn {Interface Command} {isis priority <0-127>} {}
@deffnx {Interface Command} {isis priority <0-127> [level-1 | level-2]} {}
@deffnx {Interface Command} {no isis priority} {}
@deffnx {Interface Command} {no isis priority [level-1 | level-2]} {}
Set priority for Designated Router election, globally, for the area (level-1)
or the domain (level-2).
@end deffn
@deffn {Interface Command} {isis psnp-interval <1-120>} {}
@deffnx {Interface Command} {isis psnp-interval <1-120> [level-1 | level-2]} {}
@deffnx {Interface Command} {no isis psnp-interval} {}
@deffnx {Interface Command} {no isis psnp-interval [level-1 | level-2]} {}
Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2).
@end deffn
@node Showing ISIS information
@section Showing ISIS information
@deffn {Command} {show isis summary} {}
Show summary information about ISIS.
@end deffn
@deffn {Command} {show isis hostname} {}
Show information about ISIS node.
@end deffn
@deffn {Command} {show isis interface} {}
@deffnx {Command} {show isis interface detail} {}
@deffnx {Command} {show isis interface <interface name>} {}
Show state and configuration of ISIS specified interface, or all
interfaces if no interface is given with or without details.
@end deffn
@deffn {Command} {show isis neighbor} {}
@deffnx {Command} {show isis neighbor <System Id>} {}
@deffnx {Command} {show isis neighbor detail} {}
Show state and information of ISIS specified neighbor, or all
neighbors if no system id is given with or without details.
@end deffn
@deffn {Command} {show isis database} {}
@deffnx {Command} {show isis database [detail]} {}
@deffnx {Command} {show isis database <LSP id> [detail]} {}
@deffnx {Command} {show isis database detail <LSP id>} {}
Show the ISIS database globally, for a specific LSP id without or with details.
@end deffn
@deffn {Command} {show isis topology} {}
@deffnx {Command} {show isis topology [level-1|level-2]} {}
Show topology IS-IS paths to Intermediate Systems, globally,
in area (level-1) or domain (level-2).
@end deffn
@deffn {Command} {show ip route isis} {}
Show the ISIS routing table, as determined by the most recent SPF calculation.
@end deffn
@node ISIS Traffic Engineering
@section Traffic Engineering
@deffn {ISIS Command} {mpls-te on} {}
@deffnx {ISIS Command} {no mpls-te} {}
Enable Traffic Engineering LSP flooding.
@end deffn
@deffn {ISIS Command} {mpls-te router-address <A.B.C.D>} {}
@deffnx {ISIS Command} {no mpls-te router-address} {}
Configure stable IP address for MPLS-TE.
@end deffn
@deffn {Command} {show isis mpls-te interface} {}
@deffnx {Command} {show isis mpls-te interface @var{interface}} {}
Show MPLS Traffic Engineering parameters for all or specified interface.
@end deffn
@deffn {Command} {show isis mpls-te router} {}
Show Traffic Engineering router parameters.
@end deffn
@node Debugging ISIS
@section Debugging ISIS
@deffn {Command} {debug isis adj-packets} {}
@deffnx {Command} {no debug isis adj-packets} {}
IS-IS Adjacency related packets.
@end deffn
@deffn {Command} {debug isis checksum-errors} {}
@deffnx {Command} {no debug isis checksum-errors} {}
IS-IS LSP checksum errors.
@end deffn
@deffn {Command} {debug isis events} {}
@deffnx {Command} {no debug isis events} {}
IS-IS Events.
@end deffn
@deffn {Command} {debug isis local-updates} {}
@deffnx {Command} {no debug isis local-updates} {}
IS-IS local update packets.
@end deffn
@deffn {Command} {debug isis packet-dump} {}
@deffnx {Command} {no debug isis packet-dump} {}
IS-IS packet dump.
@end deffn
@deffn {Command} {debug isis protocol-errors} {}
@deffnx {Command} {no debug isis protocol-errors} {}
IS-IS LSP protocol errors.
@end deffn
@deffn {Command} {debug isis route-events} {}
@deffnx {Command} {no debug isis route-events} {}
IS-IS Route related events.
@end deffn
@deffn {Command} {debug isis snp-packets} {}
@deffnx {Command} {no debug isis snp-packets} {}
IS-IS CSNP/PSNP packets.
@end deffn
@deffn {Command} {debug isis spf-events} {}
@deffnx {Command} {debug isis spf-statistics} {}
@deffnx {Command} {debug isis spf-triggers} {}
@deffnx {Command} {no debug isis spf-events} {}
@deffnx {Command} {no debug isis spf-statistics} {}
@deffnx {Command} {no debug isis spf-triggers} {}
IS-IS Shortest Path First Events, Timing and Statistic Data
and triggering events.
@end deffn
@deffn {Command} {debug isis update-packets} {}
@deffnx {Command} {no debug isis update-packets} {}
Update related packets.
@end deffn
@deffn {Command} {show debugging isis} {}
Print which ISIS debug level is activate.
@end deffn
@node ISIS Configuration Examples
@section ISIS Configuration Examples
A simple example, with MD5 authentication enabled:
@example
@group
!
interface eth0
ip router isis FOO
isis network point-to-point
isis circuit-type level-2-only
!
router isis FOO
net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
metric-style wide
is-type level-2-only
@end group
@end example
A Traffic Engineering configuration, with Inter-ASv2 support.
- First, the 'zebra.conf' part:
@example
@group
hostname HOSTNAME
password PASSWORD
log file /var/log/zebra.log
!
interface eth0
ip address 10.2.2.2/24
link-params
enable
metric 100
max-bw 1.25e+07
max-rsv-bw 1.25e+06
unrsv-bw 0 1.25e+06
unrsv-bw 1 1.25e+06
unrsv-bw 2 1.25e+06
unrsv-bw 3 1.25e+06
unrsv-bw 4 1.25e+06
unrsv-bw 5 1.25e+06
unrsv-bw 6 1.25e+06
unrsv-bw 7 1.25e+06
admin-grp 0xab
!
interface eth1
ip address 10.1.1.1/24
link-params
enable
metric 100
max-bw 1.25e+07
max-rsv-bw 1.25e+06
unrsv-bw 0 1.25e+06
unrsv-bw 1 1.25e+06
unrsv-bw 2 1.25e+06
unrsv-bw 3 1.25e+06
unrsv-bw 4 1.25e+06
unrsv-bw 5 1.25e+06
unrsv-bw 6 1.25e+06
unrsv-bw 7 1.25e+06
neighbor 10.1.1.2 as 65000
@end group
@end example
- Then the 'isisd.conf' itself:
@example
@group
hostname HOSTNAME
password PASSWORD
log file /var/log/isisd.log
!
!
interface eth0
ip router isis FOO
!
interface eth1
ip router isis FOO
!
!
router isis FOO
isis net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
mpls-te on
mpls-te router-address 10.1.1.1
!
line vty
@end group
@end example

930
doc/ospfd.texi Normal file
View File

@ -0,0 +1,930 @@
@cindex OSPFv2
@node OSPFv2
@chapter OSPFv2
@acronym{OSPF,Open Shortest Path First} version 2 is a routing protocol
which is described in @cite{RFC2328, OSPF Version 2}. OSPF is an
@acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP},
@acronym{OSPF} can provide scalable network support and faster
convergence times. OSPF is widely used in large networks such as
@acronym{ISP,Internet Service Provider} backbone and enterprise
networks.
@menu
* OSPF Fundamentals::
* Configuring ospfd::
* OSPF router::
* OSPF area::
* OSPF interface::
* Redistribute routes to OSPF::
* Showing OSPF information::
* Opaque LSA::
* OSPF Traffic Engineering::
* Router Information::
* Debugging OSPF::
* OSPF Configuration Examples::
@end menu
@include ospf_fundamentals.texi
@node Configuring ospfd
@section Configuring ospfd
There are no @command{ospfd} specific options. Common options can be
specified (@pxref{Common Invocation Options}) to @command{ospfd}.
@command{ospfd} needs to acquire interface information from
@command{zebra} in order to function. Therefore @command{zebra} must be
running before invoking @command{ospfd}. Also, if @command{zebra} is
restarted then @command{ospfd} must be too.
Like other daemons, @command{ospfd} configuration is done in @acronym{OSPF}
specific configuration file @file{ospfd.conf}.
@node OSPF router
@section OSPF router
To start OSPF process you have to specify the OSPF router. As of this
writing, @command{ospfd} does not support multiple OSPF processes.
@deffn Command {router ospf} {}
@deffnx Command {no router ospf} {}
Enable or disable the OSPF process. @command{ospfd} does not yet
support multiple OSPF processes. So you can not specify an OSPF process
number.
@end deffn
@deffn {OSPF Command} {ospf router-id @var{a.b.c.d}} {}
@deffnx {OSPF Command} {no ospf router-id} {}
@anchor{ospf router-id}This sets the router-ID of the OSPF process. The
router-ID may be an IP address of the router, but need not be - it can
be any arbitrary 32bit number. However it MUST be unique within the
entire OSPF domain to the OSPF speaker - bad things will happen if
multiple OSPF speakers are configured with the same router-ID! If one
is not specified then @command{ospfd} will obtain a router-ID
automatically from @command{zebra}.
@end deffn
@deffn {OSPF Command} {ospf abr-type @var{type}} {}
@deffnx {OSPF Command} {no ospf abr-type @var{type}} {}
@var{type} can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types
are equivalent.
The OSPF standard for ABR behaviour does not allow an ABR to consider
routes through non-backbone areas when its links to the backbone are
down, even when there are other ABRs in attached non-backbone areas
which still can reach the backbone - this restriction exists primarily
to ensure routing-loops are avoided.
With the "Cisco" or "IBM" ABR type, the default in this release of
Frr, this restriction is lifted, allowing an ABR to consider
summaries learnt from other ABRs through non-backbone areas, and hence
route via non-backbone areas as a last resort when, and only when,
backbone links are down.
Note that areas with fully-adjacent virtual-links are considered to be
"transit capable" and can always be used to route backbone traffic, and
hence are unaffected by this setting (@pxref{OSPF virtual-link}).
More information regarding the behaviour controlled by this command can
be found in @cite{RFC 3509, Alternative Implementations of OSPF Area
Border Routers}, and @cite{draft-ietf-ospf-shortcut-abr-02.txt}.
Quote: "Though the definition of the @acronym{ABR,Area Border Router}
in the OSPF specification does not require a router with multiple
attached areas to have a backbone connection, it is actually
necessary to provide successful routing to the inter-area and
external destinations. If this requirement is not met, all traffic
destined for the areas not connected to such an ABR or out of the
OSPF domain, is dropped. This document describes alternative ABR
behaviors implemented in Cisco and IBM routers."
@end deffn
@deffn {OSPF Command} {ospf rfc1583compatibility} {}
@deffnx {OSPF Command} {no ospf rfc1583compatibility} {}
@cite{RFC2328}, the sucessor to @cite{RFC1583}, suggests according
to section G.2 (changes) in section 16.4 a change to the path
preference algorithm that prevents possible routing loops that were
possible in the old version of OSPFv2. More specifically it demands
that inter-area paths and intra-area backbone path are now of equal preference
but still both preferred to external paths.
This command should NOT be set normally.
@end deffn
@deffn {OSPF Command} {log-adjacency-changes [detail]} {}
@deffnx {OSPF Command} {no log-adjacency-changes [detail]} {}
Configures ospfd to log changes in adjacency. With the optional
detail argument, all changes in adjacency status are shown. Without detail,
only changes to full or regressions are shown.
@end deffn
@deffn {OSPF Command} {passive-interface @var{interface}} {}
@deffnx {OSPF Command} {no passive-interface @var{interface}} {}
@anchor{OSPF passive-interface} Do not speak OSPF interface on the
given interface, but do advertise the interface as a stub link in the
router-@acronym{LSA,Link State Advertisement} for this router. This
allows one to advertise addresses on such connected interfaces without
having to originate AS-External/Type-5 LSAs (which have global flooding
scope) - as would occur if connected addresses were redistributed into
OSPF (@pxref{Redistribute routes to OSPF})@. This is the only way to
advertise non-OSPF links into stub areas.
@end deffn
@deffn {OSPF Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {}
@deffnx {OSPF Command} {no timers throttle spf} {}
This command sets the initial @var{delay}, the @var{initial-holdtime}
and the @var{maximum-holdtime} between when SPF is calculated and the
event which triggered the calculation. The times are specified in
milliseconds and must be in the range of 0 to 600000 milliseconds.
The @var{delay} specifies the minimum amount of time to delay SPF
calculation (hence it affects how long SPF calculation is delayed after
an event which occurs outside of the holdtime of any previous SPF
calculation, and also serves as a minimum holdtime).
Consecutive SPF calculations will always be seperated by at least
'hold-time' milliseconds. The hold-time is adaptive and initially is
set to the @var{initial-holdtime} configured with the above command.
Events which occur within the holdtime of the previous SPF calculation
will cause the holdtime to be increased by @var{initial-holdtime}, bounded
by the @var{maximum-holdtime} configured with this command. If the adaptive
hold-time elapses without any SPF-triggering event occuring then
the current holdtime is reset to the @var{initial-holdtime}. The current
holdtime can be viewed with @ref{show ip ospf}, where it is expressed as
a multiplier of the @var{initial-holdtime}.
@example
@group
router ospf
timers throttle spf 200 400 10000
@end group
@end example
In this example, the @var{delay} is set to 200ms, the @var{initial
holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence
there will always be at least 200ms between an event which requires SPF
calculation and the actual SPF calculation. Further consecutive SPF
calculations will always be seperated by between 400ms to 10s, the
hold-time increasing by 400ms each time an SPF-triggering event occurs
within the hold-time of the previous SPF calculation.
This command supercedes the @command{timers spf} command in previous Frr
releases.
@end deffn
@deffn {OSPF Command} {max-metric router-lsa [on-startup|on-shutdown] <5-86400>} {}
@deffnx {OSPF Command} {max-metric router-lsa administrative} {}
@deffnx {OSPF Command} {no max-metric router-lsa [on-startup|on-shutdown|administrative]} {}
This enables @cite{RFC3137, OSPF Stub Router Advertisement} support,
where the OSPF process describes its transit links in its router-LSA as
having infinite distance so that other routers will avoid calculating
transit paths through the router while still being able to reach
networks through the router.
This support may be enabled administratively (and indefinitely) or
conditionally. Conditional enabling of max-metric router-lsas can be
for a period of seconds after startup and/or for a period of seconds
prior to shutdown.
Enabling this for a period after startup allows OSPF to converge fully
first without affecting any existing routes used by other routers,
while still allowing any connected stub links and/or redistributed
routes to be reachable. Enabling this for a period of time in advance
of shutdown allows the router to gracefully excuse itself from the OSPF
domain.
Enabling this feature administratively allows for administrative
intervention for whatever reason, for an indefinite period of time.
Note that if the configuration is written to file, this administrative
form of the stub-router command will also be written to file. If
@command{ospfd} is restarted later, the command will then take effect
until manually deconfigured.
Configured state of this feature as well as current status, such as the
number of second remaining till on-startup or on-shutdown ends, can be
viewed with the @ref{show ip ospf} command.
@end deffn
@deffn {OSPF Command} {auto-cost reference-bandwidth <1-4294967>} {}
@deffnx {OSPF Command} {no auto-cost reference-bandwidth} {}
@anchor{OSPF auto-cost reference-bandwidth}This sets the reference
bandwidth for cost calculations, where this bandwidth is considered
equivalent to an OSPF cost of 1, specified in Mbits/s. The default is
100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a
cost of 1. Cost of lower bandwidth links will be scaled with reference
to this cost).
This configuration setting MUST be consistent across all routers within the
OSPF domain.
@end deffn
@deffn {OSPF Command} {network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
@deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
@anchor{OSPF network command}
This command specifies the OSPF enabled interface(s). If the interface has
an address from range 192.168.1.0/24 then the command below enables ospf
on this interface so router can provide network information to the other
ospf routers via this interface.
@example
@group
router ospf
network 192.168.1.0/24 area 0.0.0.0
@end group
@end example
Prefix length in interface must be equal or bigger (ie. smaller network) than
prefix length in network statement. For example statement above doesn't enable
ospf on interface with address 192.168.1.1/23, but it does on interface with
address 192.168.1.129/25.
Note that the behavior when there is a peer address
defined on an interface changed after release 0.99.7.
Currently, if a peer prefix has been configured,
then we test whether the prefix in the network command contains
the destination prefix. Otherwise, we test whether the network command prefix
contains the local address prefix of the interface.
In some cases it may be more convenient to enable OSPF on a per
interface/subnet basis (@pxref{OSPF ip ospf area command}).
@end deffn
@node OSPF area
@section OSPF area
@deffn {OSPF Command} {area @var{a.b.c.d} range @var{a.b.c.d/m}} {}
@deffnx {OSPF Command} {area <0-4294967295> range @var{a.b.c.d/m}} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} range @var{a.b.c.d/m}} {}
@deffnx {OSPF Command} {no area <0-4294967295> range @var{a.b.c.d/m}} {}
Summarize intra area paths from specified area into one Type-3 summary-LSA
announced to other areas. This command can be used only in ABR and ONLY
router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can
be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS.
Summarizing Type-7 AS-external-LSAs isn't supported yet by Frr.
@example
@group
router ospf
network 192.168.1.0/24 area 0.0.0.0
network 10.0.0.0/8 area 0.0.0.10
area 0.0.0.10 range 10.0.0.0/8
@end group
@end example
With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is
announced into backbone area if area 0.0.0.10 contains at least one intra-area
network (ie. described with router or network LSA) from this range.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {}
Instead of summarizing intra area paths filter them - ie. intra area paths from this
range are not advertised into other areas.
This command makes sense in ABR only.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {}
Substitute summarized prefix with another prefix.
@example
@group
router ospf
network 192.168.1.0/24 area 0.0.0.0
network 10.0.0.0/8 area 0.0.0.10
area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8
@end group
@end example
One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if
area 0.0.0.10 contains at least one intra-area network (ie. described with router-LSA or
network-LSA) from range 10.0.0.0/8.
This command makes sense in ABR only.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {}
@deffnx {OSPF Command} {area <0-4294967295> virtual-link @var{a.b.c.d}} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {}
@deffnx {OSPF Command} {no area <0-4294967295> virtual-link @var{a.b.c.d}} {}
@anchor{OSPF virtual-link}
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} shortcut} {}
@deffnx {OSPF Command} {area <0-4294967295> shortcut} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} shortcut} {}
@deffnx {OSPF Command} {no area <0-4294967295> shortcut} {}
Configure the area as Shortcut capable. See @cite{RFC3509}. This requires
that the 'abr-type' be set to 'shortcut'.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} stub} {}
@deffnx {OSPF Command} {area <0-4294967295> stub} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} stub} {}
@deffnx {OSPF Command} {no area <0-4294967295> stub} {}
Configure the area to be a stub area. That is, an area where no router
originates routes external to OSPF and hence an area where all external
routes are via the ABR(s). Hence, ABRs for such an area do not need
to pass AS-External LSAs (type-5s) or ASBR-Summary LSAs (type-4) into the
area. They need only pass Network-Summary (type-3) LSAs into such an area,
along with a default-route summary.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} stub no-summary} {}
@deffnx {OSPF Command} {area <0-4294967295> stub no-summary} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} stub no-summary} {}
@deffnx {OSPF Command} {no area <0-4294967295> stub no-summary} {}
Prevents an @command{ospfd} ABR from injecting inter-area
summaries into the specified stub area.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} default-cost <0-16777215>} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} default-cost <0-16777215>} {}
Set the cost of default-summary LSAs announced to stubby areas.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} export-list NAME} {}
@deffnx {OSPF Command} {area <0-4294967295> export-list NAME} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} export-list NAME} {}
@deffnx {OSPF Command} {no area <0-4294967295> export-list NAME} {}
Filter Type-3 summary-LSAs announced to other areas originated from intra-
area paths from specified area.
@example
@group
router ospf
network 192.168.1.0/24 area 0.0.0.0
network 10.0.0.0/8 area 0.0.0.10
area 0.0.0.10 export-list foo
!
access-list foo permit 10.10.0.0/16
access-list foo deny any
@end group
@end example
With example above any intra-area paths from area 0.0.0.10 and from range
10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into
other areas as Type-3 summary-LSA's, but any others (for example 10.11.0.0/16
or 10.128.30.16/30) aren't.
This command is only relevant if the router is an ABR for the specified
area.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} import-list NAME} {}
@deffnx {OSPF Command} {area <0-4294967295> import-list NAME} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} import-list NAME} {}
@deffnx {OSPF Command} {no area <0-4294967295> import-list NAME} {}
Same as export-list, but it applies to paths announced into specified area as
Type-3 summary-LSAs.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME in} {}
@deffnx {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME out} {}
@deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME in} {}
@deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME out} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME in} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME out} {}
@deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME in} {}
@deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME out} {}
Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
makes sense in ABR only.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} authentication} {}
@deffnx {OSPF Command} {area <0-4294967295> authentication} {}
@deffnx {OSPF Command} {no area @var{a.b.c.d} authentication} {}
@deffnx {OSPF Command} {no area <0-4294967295> authentication} {}
Specify that simple password authentication should be used for the given
area.
@end deffn
@deffn {OSPF Command} {area @var{a.b.c.d} authentication message-digest} {}
@deffnx {OSPF Command} {area <0-4294967295> authentication message-digest} {}
@anchor{area authentication message-digest}Specify that OSPF packets
must be authenticated with MD5 HMACs within the given area. Keying
material must also be configured on a per-interface basis (@pxref{ip
ospf message-digest-key}).
MD5 authentication may also be configured on a per-interface basis
(@pxref{ip ospf authentication message-digest}). Such per-interface
settings will override any per-area authentication setting.
@end deffn
@node OSPF interface
@section OSPF interface
@deffn {Interface Command} {ip ospf area @var{AREA} [@var{ADDR}]} {}
@deffnx {Interface Command} {no ip ospf area [@var{ADDR}]} {}
@anchor{OSPF ip ospf area command}
Enable OSPF on the interface, optionally restricted to just the IP address
given by @var{ADDR}, putting it in the @var{AREA} area. Per interface area
settings take precedence to network commands (@pxref{OSPF network command}).
If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF
via this command may result in a slight performance improvement.
@end deffn
@deffn {Interface Command} {ip ospf authentication-key @var{AUTH_KEY}} {}
@deffnx {Interface Command} {no ip ospf authentication-key} {}
Set OSPF authentication key to a simple password. After setting @var{AUTH_KEY},
all OSPF packets are authenticated. @var{AUTH_KEY} has length up to 8 chars.
Simple text password authentication is insecure and deprecated in favour of
MD5 HMAC authentication (@pxref{ip ospf authentication message-digest}).
@end deffn
@deffn {Interface Command} {ip ospf authentication message-digest} {}
@anchor{ip ospf authentication message-digest}Specify that MD5 HMAC
authentication must be used on this interface. MD5 keying material must
also be configured (@pxref{ip ospf message-digest-key}). Overrides any
authentication enabled on a per-area basis (@pxref{area
authentication message-digest}).
Note that OSPF MD5 authentication requires that time never go backwards
(correct time is NOT important, only that it never goes backwards), even
across resets, if ospfd is to be able to promptly reestabish adjacencies
with its neighbours after restarts/reboots. The host should have system
time be set at boot from an external or non-volatile source (eg battery backed clock, NTP,
etc.) or else the system clock should be periodically saved to non-volative
storage and restored at boot if MD5 authentication is to be expected to work
reliably.
@end deffn
@deffn {Interface Command} {ip ospf message-digest-key KEYID md5 KEY} {}
@deffnx {Interface Command} {no ip ospf message-digest-key} {}
@anchor{ip ospf message-digest-key}Set OSPF authentication key to a
cryptographic password. The cryptographic algorithm is MD5.
KEYID identifies secret key used to create the message digest. This ID
is part of the protocol and must be consistent across routers on a
link.
KEY is the actual message digest key, of up to 16 chars (larger strings
will be truncated), and is associated with the given KEYID.
@end deffn
@deffn {Interface Command} {ip ospf cost <1-65535>} {}
@deffnx {Interface Command} {no ip ospf cost} {}
Set link cost for the specified interface. The cost value is set to router-LSA's
metric field and used for SPF calculation.
@end deffn
@deffn {Interface Command} {ip ospf dead-interval <1-65535>} {}
@deffnx {Interface Command} {ip ospf dead-interval minimal hello-multiplier <2-20>} {}
@deffnx {Interface Command} {no ip ospf dead-interval} {}
@anchor{ip ospf dead-interval minimal} Set number of seconds for
RouterDeadInterval timer value used for Wait Timer and Inactivity
Timer. This value must be the same for all routers attached to a
common network. The default value is 40 seconds.
If 'minimal' is specified instead, then the dead-interval is set to 1
second and one must specify a hello-multiplier. The hello-multiplier
specifies how many Hellos to send per second, from 2 (every 500ms) to
20 (every 50ms). Thus one can have 1s convergence time for OSPF. If this form
is specified, then the hello-interval advertised in Hello packets is set to
0 and the hello-interval on received Hello packets is not checked, thus
the hello-multiplier need NOT be the same across multiple routers on a common
link.
@end deffn
@deffn {Interface Command} {ip ospf hello-interval <1-65535>} {}
@deffnx {Interface Command} {no ip ospf hello-interval} {}
Set number of seconds for HelloInterval timer value. Setting this value,
Hello packet will be sent every timer value seconds on the specified interface.
This value must be the same for all routers attached to a common network.
The default value is 10 seconds.
This command has no effect if @ref{ip ospf dead-interval minimal} is also
specified for the interface.
@end deffn
@deffn {Interface Command} {ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)} {}
@deffnx {Interface Command} {no ip ospf network} {}
Set explicitly network type for specifed interface.
@end deffn
@deffn {Interface Command} {ip ospf priority <0-255>} {}
@deffnx {Interface Command} {no ip ospf priority} {}
Set RouterPriority integer value. The router with the highest priority
will be more eligible to become Designated Router. Setting the value
to 0, makes the router ineligible to become Designated Router. The
default value is 1.
@end deffn
@deffn {Interface Command} {ip ospf retransmit-interval <1-65535>} {}
@deffnx {Interface Command} {no ip ospf retransmit interval} {}
Set number of seconds for RxmtInterval timer value. This value is used
when retransmitting Database Description and Link State Request packets.
The default value is 5 seconds.
@end deffn
@deffn {Interface Command} {ip ospf transmit-delay} {}
@deffnx {Interface Command} {no ip ospf transmit-delay} {}
Set number of seconds for InfTransDelay value. LSAs' age should be
incremented by this value when transmitting.
The default value is 1 seconds.
@end deffn
@deffn {Interface Command} {ip ospf area (A.B.C.D|<0-4294967295>)} {}
@deffnx {Interface Command} {no ip ospf area} {}
Enable ospf on an interface and set associated area.
@end deffn
@node Redistribute routes to OSPF
@section Redistribute routes to OSPF
@deffn {OSPF Command} {redistribute (kernel|connected|static|rip|bgp)} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) @var{route-map}} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map @var{word}} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map @var{word}} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>} {}
@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map @var{word}} {}
@deffnx {OSPF Command} {no redistribute (kernel|connected|static|rip|bgp)} {}
@anchor{OSPF redistribute}Redistribute routes of the specified protocol
or kind into OSPF, with the metric type and metric set if specified,
filtering the routes using the given route-map if specified.
Redistributed routes may also be filtered with distribute-lists, see
@ref{ospf distribute-list}.
Redistributed routes are distributed as into OSPF as Type-5 External
LSAs into links to areas that accept external routes, Type-7 External LSAs
for NSSA areas and are not redistributed at all into Stub areas, where
external routes are not permitted.
Note that for connected routes, one may instead use
@dfn{passive-interface}, see @ref{OSPF passive-interface}.
@end deffn
@deffn {OSPF Command} {default-information originate} {}
@deffnx {OSPF Command} {default-information originate metric <0-16777214>} {}
@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2)} {}
@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2) route-map @var{word}} {}
@deffnx {OSPF Command} {default-information originate always} {}
@deffnx {OSPF Command} {default-information originate always metric <0-16777214>} {}
@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2)} {}
@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2) route-map @var{word}} {}
@deffnx {OSPF Command} {no default-information originate} {}
Originate an AS-External (type-5) LSA describing a default route into
all external-routing capable areas, of the specified metric and metric
type. If the 'always' keyword is given then the default is always
advertised, even when there is no default present in the routing table.
@end deffn
@deffn {OSPF Command} {distribute-list NAME out (kernel|connected|static|rip|ospf} {}
@deffnx {OSPF Command} {no distribute-list NAME out (kernel|connected|static|rip|ospf} {}
@anchor{ospf distribute-list}Apply the access-list filter, NAME, to
redistributed routes of the given type before allowing the routes to
redistributed into OSPF (@pxref{OSPF redistribute}).
@end deffn
@deffn {OSPF Command} {default-metric <0-16777214>} {}
@deffnx {OSPF Command} {no default-metric} {}
@end deffn
@deffn {OSPF Command} {distance <1-255>} {}
@deffnx {OSPF Command} {no distance <1-255>} {}
@end deffn
@deffn {OSPF Command} {distance ospf (intra-area|inter-area|external) <1-255>} {}
@deffnx {OSPF Command} {no distance ospf} {}
@end deffn
@deffn {Command} {router zebra} {}
@deffnx {Command} {no router zebra} {}
@end deffn
@node Showing OSPF information
@section Showing OSPF information
@deffn {Command} {show ip ospf} {}
@anchor{show ip ospf}Show information on a variety of general OSPF and
area state and configuration information.
@end deffn
@deffn {Command} {show ip ospf interface [INTERFACE]} {}
Show state and configuration of OSPF the specified interface, or all
interfaces if no interface is given.
@end deffn
@deffn {Command} {show ip ospf neighbor} {}
@deffnx {Command} {show ip ospf neighbor INTERFACE} {}
@deffnx {Command} {show ip ospf neighbor detail} {}
@deffnx {Command} {show ip ospf neighbor INTERFACE detail} {}
@end deffn
@deffn {Command} {show ip ospf database} {}
@end deffn
@deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {}
@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {}
@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {}
@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {}
@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {}
@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {}
@end deffn
@deffn {Command} {show ip ospf database max-age} {}
@end deffn
@deffn {Command} {show ip ospf database self-originate} {}
@end deffn
@deffn {Command} {show ip ospf route} {}
Show the OSPF routing table, as determined by the most recent SPF calculation.
@end deffn
@node Opaque LSA
@section Opaque LSA
@deffn {OSPF Command} {ospf opaque-lsa} {}
@deffnx {OSPF Command} {capability opaque} {}
@deffnx {OSPF Command} {no ospf opaque-lsa} {}
@deffnx {OSPF Command} {no capability opaque} {}
@command{ospfd} support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration file. Alternate command could be "mpls-te on" (@ref{OSPF Traffic Engineering}).
@end deffn
@deffn {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external)} {}
@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id}} {}
@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} adv-router @var{adv-router}} {}
@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router @var{adv-router}} {}
@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} self-originate} {}
@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate} {}
Show Opaque LSA from the database.
@end deffn
@node OSPF Traffic Engineering
@section Traffic Engineering
@deffn {OSPF Command} {mpls-te on} {}
@deffnx {OSPF Command} {no mpls-te} {}
Enable Traffic Engineering LSA flooding.
@end deffn
@deffn {OSPF Command} {mpls-te router-address <A.B.C.D>} {}
@deffnx {OSPF Command} {no mpls-te} {}
Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE)
option 1 (Router-Address).
@end deffn
@deffn {OSPF Command} {mpls-te inter-as area <area-id>|as} {}
@deffnx {OSPF Command} {no mpls-te inter-as} {}
Enable RFC5392 suuport - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link.
2 modes are supported: AREA and AS; LSA are flood in AREA <area-id> with Opaque Type-10,
respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6.
@end deffn
@deffn {Command} {show ip ospf mpls-te interface} {}
@deffnx {Command} {show ip ospf mpls-te interface @var{interface}} {}
Show MPLS Traffic Engineering parameters for all or specified interface.
@end deffn
@deffn {Command} {show ip ospf mpls-te router} {}
Show Traffic Engineering router parameters.
@end deffn
@node Router Information
@section Router Information
@deffn {OSPF Command} {router-info [as | area <A.B.C.D>]} {}
@deffnx {OSPF Command} {no router-info} {}
Enable Router Information (RFC4970) LSA advertisement with AS scope (default) or Area scope flooding
when area is specified.
@end deffn
@deffn {OSPF Command} {pce address <A.B.C.D>} {}
@deffnx {OSPF Command} {no pce address} {}
@deffnx {OSPF Command} {pce domain as <0-65535>} {}
@deffnx {OSPF Command} {no pce domain as <0-65535>} {}
@deffnx {OSPF Command} {pce neighbor as <0-65535>} {}
@deffnx {OSPF Command} {no pce neighbor as <0-65535>} {}
@deffnx {OSPF Command} {pce flag BITPATTERN} {}
@deffnx {OSPF Command} {no pce flag} {}
@deffnx {OSPF Command} {pce scope BITPATTERN} {}
@deffnx {OSPF Command} {no pce scope} {}
The commands are conform to RFC 5088 and allow OSPF router announce Path Compuatation Elemenent (PCE) capabilities
through the Router Information (RI) LSA. Router Information must be enable prior to this. The command set/unset
respectively the PCE IP adress, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope.
For flag and scope, please refer to RFC5088 for the BITPATTERN recognition. Multiple 'pce neighbor' command could
be specified in order to specify all PCE neighbours.
@end deffn
@deffn {Command} {show ip ospf router-info} {}
Show Router Capabilities flag.
@end deffn
@deffn {Command} {show ip ospf router-info pce} {}
Show Router Capabilities PCE parameters.
@end deffn
@node Debugging OSPF
@section Debugging OSPF
@deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {}
@deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {}
Dump Packet for debugging
@end deffn
@deffn {Command} {debug ospf ism} {}
@deffnx {Command} {debug ospf ism (status|events|timers)} {}
@deffnx {Command} {no debug ospf ism} {}
@deffnx {Command} {no debug ospf ism (status|events|timers)} {}
Show debug information of Interface State Machine
@end deffn
@deffn {Command} {debug ospf nsm} {}
@deffnx {Command} {debug ospf nsm (status|events|timers)} {}
@deffnx {Command} {no debug ospf nsm} {}
@deffnx {Command} {no debug ospf nsm (status|events|timers)} {}
Show debug information of Network State Machine
@end deffn
@deffn {Command} {debug ospf event} {}
@deffnx {Command} {no debug ospf event} {}
Show debug information of OSPF event
@end deffn
@deffn {Command} {debug ospf nssa} {}
@deffnx {Command} {no debug ospf nssa} {}
Show debug information about Not So Stub Area
@end deffn
@deffn {Command} {debug ospf lsa} {}
@deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {}
@deffnx {Command} {no debug ospf lsa} {}
@deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {}
Show debug detail of Link State messages
@end deffn
@deffn {Command} {debug ospf te} {}
@deffnx {Command} {no debug ospf te} {}
Show debug information about Traffic Engineering LSA
@end deffn
@deffn {Command} {debug ospf zebra} {}
@deffnx {Command} {debug ospf zebra (interface|redistribute)} {}
@deffnx {Command} {no debug ospf zebra} {}
@deffnx {Command} {no debug ospf zebra (interface|redistribute)} {}
Show debug information of ZEBRA API
@end deffn
@deffn {Command} {show debugging ospf} {}
@end deffn
@node OSPF Configuration Examples
@section OSPF Configuration Examples
A simple example, with MD5 authentication enabled:
@example
@group
!
interface bge0
ip ospf authentication message-digest
ip ospf message-digest-key 1 md5 ABCDEFGHIJK
!
router ospf
network 192.168.0.0/16 area 0.0.0.1
area 0.0.0.1 authentication message-digest
@end group
@end example
An @acronym{ABR} router, with MD5 authentication and performing summarisation
of networks between the areas:
@example
@group
!
password ABCDEF
log file /var/log/frr/ospfd.log
service advanced-vty
!
interface eth0
ip ospf authentication message-digest
ip ospf message-digest-key 1 md5 ABCDEFGHIJK
!
interface ppp0
!
interface br0
ip ospf authentication message-digest
ip ospf message-digest-key 2 md5 XYZ12345
!
router ospf
ospf router-id 192.168.0.1
redistribute connected
passive interface ppp0
network 192.168.0.0/24 area 0.0.0.0
network 10.0.0.0/16 area 0.0.0.0
network 192.168.1.0/24 area 0.0.0.1
area 0.0.0.0 authentication message-digest
area 0.0.0.0 range 10.0.0.0/16
area 0.0.0.0 range 192.168.0.0/24
area 0.0.0.1 authentication message-digest
area 0.0.0.1 range 10.2.0.0/16
!
@end group
@end example
A Traffic Engineering configuration, with Inter-ASv2 support.
- First, the 'zebra.conf' part:
@example
@group
hostname HOSTNAME
password PASSWORD
log file /var/log/zebra.log
!
interface eth0
ip address 198.168.1.1/24
link-params
enable
admin-grp 0xa1
metric 100
max-bw 1.25e+07
max-rsv-bw 1.25e+06
unrsv-bw 0 1.25e+06
unrsv-bw 1 1.25e+06
unrsv-bw 2 1.25e+06
unrsv-bw 3 1.25e+06
unrsv-bw 4 1.25e+06
unrsv-bw 5 1.25e+06
unrsv-bw 6 1.25e+06
unrsv-bw 7 1.25e+06
!
interface eth1
ip address 192.168.2.1/24
link-params
enable
metric 10
max-bw 1.25e+07
max-rsv-bw 1.25e+06
unrsv-bw 0 1.25e+06
unrsv-bw 1 1.25e+06
unrsv-bw 2 1.25e+06
unrsv-bw 3 1.25e+06
unrsv-bw 4 1.25e+06
unrsv-bw 5 1.25e+06
unrsv-bw 6 1.25e+06
unrsv-bw 7 1.25e+06
neighbor 192.168.2.2 as 65000
@end group
@end example
- Then the 'ospfd.conf' itself:
@example
@group
hostname HOSTNAME
password PASSWORD
log file /var/log/ospfd.log
!
!
interface eth0
ip ospf hello-interval 60
ip ospf dead-interval 240
!
interface eth1
ip ospf hello-interval 60
ip ospf dead-interval 240
!
!
router ospf
ospf router-id 192.168.1.1
network 192.168.0.0/16 area 1
ospf opaque-lsa
mpls-te
mpls-te router-address 192.168.1.1
mpls-te inter-as area 1
!
line vty
@end group
@end example
A router information example with PCE advsertisement:
@example
@group
!
router ospf
ospf router-id 192.168.1.1
network 192.168.0.0/16 area 1
capability opaque
mpls-te
mpls-te router-address 192.168.1.1
router-info area 0.0.0.1
pce address 192.168.1.1
pce flag 0x80
pce domain as 65400
pce neighbor as 65500
pce neighbor as 65200
pce scope 0x80
!
@end group
@end example

366
doc/pimd.texi Normal file
View File

@ -0,0 +1,366 @@
@c -*-texinfo-*-
@c This is part of the Frr Manual.
@c @value{COPYRIGHT_STR}
@c See file frr.texi for copying conditions.
@node PIM
@chapter PIM
PIM -- Protocol Independent Multicast
@command{pimd} supports pim-sm as well as igmp v2 and v3. pim is
vrf aware and can work within the context of vrf's in order to
do S,G mrouting.
@menu
* Starting and Stopping pimd::
* PIM Configuration::
* PIM Interface Configuration::
* PIM Multicast RIB insertion::
* Show PIM Information::
* PIM Debug Commands::
@end menu
@node Starting and Stopping pimd
@section Starting and Stopping pimd
The default configuration file name of @command{pimd}'s is
@file{pimd.conf}. When invocation @command{pimd} searches directory
@value{INSTALL_PREFIX_ETC}. If @file{pimd.conf} is not there
then next search current directory.
@command{pimd} requires zebra for proper operation. Additionally
@command{pimd} depends on routing properly setup and working
in the network that it is working on.
@example
@group
# zebra -d
# pimd -d
@end group
@end example
Please note that @command{zebra} must be invoked before @command{pimd}.
To stop @command{pimd}. Please use @command{kill `cat
/var/run/pimd.pid`}. Certain signals have special meanings to @command{pimd}.
@table @samp
@item SIGUSR1
Rotate @command{pimd} logfile.
@item SIGINT
@itemx SIGTERM
@command{pimd} sweeps all installed PIM mroutes then terminates properly.
@end table
@command{pimd} invocation options. Common options that can be specified
(@pxref{Common Invocation Options}).
@node PIM Configuration
@deffn Command {ip pim rp A.B.C.D A.B.C.D/M} {}
In order to use pim, it is necessary to configure a RP for join
messages to be sent to. Currently the only methodology to
do this is via static rp commands. All routers in the
pim network must agree on these values. The first ip address
is the RP's address and the second value is the matching
prefix of group ranges covered. This command is vrf aware,
to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim spt-switchover infinity-and-beyond} {}
On the last hop router if it is desired to not switch over
to the SPT tree. Configure this command. This command is
vrf aware, to configure for a vrf, enter the vrf submode.
#end deffn
@deffn Comand {ip pim ecmp} {}
If pim has the a choice of ECMP nexthops for a particular
RPF, pim will cause S,G flows to be spread out amongst
the nexthops. If this command is not specified then
the first nexthop found will be used. This command
is vrf aware, to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim ecmp rebalance} {}
If pim is using ECMP and an interface goes down, cause
pim to rebalance all S,G flows aross the remaining
nexthops. If this command is not configured pim only
modifies those S,G flows that were using the interface
that went down. This command is vrf aware, to configure
for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim join-prune-interval (60-600)} {}
Modify the join/prune interval that pim uses to the
new value. Time is specified in seconds. This command
is vrf aware, to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim keep-alive-timer (31-60000)} {}
Modify the time out value for a S,G flow from 31-60000
seconds. 31 seconds is choosen for a lower bound
because some hardware platforms cannot see data flowing
in better than 30 second chunks. This comand is vrf
aware, to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim packets (1-100)} {}
When processing packets from a neighbor process the
number of packets incoming at one time before moving
on to the next task. The default value is 3 packets.
This command is only useful at scale when you can
possibly have a large number of pim control packets
flowing. This command is vrf aware, to configure for
a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim register-suppress-time (5-60000)} {}
Modify the time that pim will register suppress a FHR
will send register notifications to the kernel. This command
is vrf aware, to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim send-v6-secondary} {}
When sending pim hello packets tell pim to send
any v6 secondary addresses on the interface. This
information is used to allow pim to use v6 nexthops
in it's decision for RPF lookup. This command
is vrf aware, to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip pim ssm prefix-list WORD} {}
Specify a range of group addresses via a prefix-list
that forces pim to never do SM over. This command
is vrf aware, to configure for a vrf, enter the vrf submode.
@end deffn
@deffn Command {ip multicast rpf-lookup-mode WORD} {}
Modify how PIM does RPF lookups in the zebra routing table.
You can use these choices:
@table @lookup_modes
@item longer-prefix
Lookup the RPF in both tables using the longer prefix as a match
@item lower-distance
Lookup the RPF in both tables using the lower distance as a match
@item mrib-only
Lookup in the Multicast RIB only
@item mrib-then-urib
Lookup in the Multicast RIB then the Unicast Rib, returning first found.
This is the default value for lookup if this command is not entered
@item urib-only
Lookup in the Unicast Rib only.
@end table
@end deffn
@node PIM Interface Configuration
@section PIM Interface Configuration
PIM interface commands allow you to configure an
interface as either a Receiver or a interface
that you would like to form pim neighbors on. If the
interface is in a vrf, enter the interface command with
the vrf keyword at the end.
@deffn {PIM Interface Command] {ip pim bfd} {}
Turns on BFD support for PIM for this interface.
@end deffn
@deffn {PIM Interface Command} {ip pim drpriority (1-4294967295)} {}
Set the DR Priority for the interface. This command is useful
to allow the user to influence what node becomes the DR for a
lan segment.
@end deffn
@deffn {PIM Interface Command} {ip pim hello (1-180) (1-180)} {}
Set the pim hello and hold interval for a interface.
@end deffn
@deffn {PIM Interface Command} {ip pim sm} {}
Tell pim that we would like to use this interface to form
pim neighbors over. Please note we will *not* accept
igmp reports over this interface with this command.
@end deffn
@deffn {PIM Interface Command} {ip igmp} {}
Tell pim to receive IGMP reports and Query on this
interface. The default version is v3. This command
is useful on the LHR.
@end deffn
@deffn {PIM Interface Command} {ip igmp query-interval (1-1800)} {}
Set the IGMP query interval that PIM will use.
@end deffn
@deffn {PIM Interface Command} {ip igmp query-max-response-time (10-250)} {}
Set the IGMP query response timeout value. If an report is not returned
in the specified time we will assume the S,G or *,G has timed out.
@end deffn
@deffn {PIM Interface Command} {ip igmp version (2-3)} {}
Set the IGMP version used on this interface. The default value
is 3.
@end deffn
@deffn {PIM Interface Command} {ip multicat boundary oil WORD} {}
Set a pim multicast boundary, based upon the WORD prefix-list. If
a pim join or IGMP report is received on this interface and the Group
is denyed by the prefix-list, PIM will ignore the join or report.
@end deffn
@node PIM Multicast RIB insertion::
@section PIM Multicast RIB insertion::
In order to influence Multicast RPF lookup, it is possible to insert
into zebra routes for the Multicast RIB. These routes are only
used for RPF lookup and will not be used by zebra for insertion
into the kernel *or* for normal rib processing. As such it is
possible to create weird states with these commands. Use with
caution. Most of the time this will not be necessary.
@deffn {PIM Multicast RIB insertion} {ip mroute A.B.C.D/M A.B.C.D (1-255)} {}
Insert into the Multicast Rib Route A.B.C.D/M with specified nexthop. The distance can be specified as well if desired.
@end deffn
@deffn {PIM Multicast RIB insertion} {ip mroute A.B.C.D/M INTERFACE (1-255)} {}
Insert into the Multicast Rib Route A.B.C.D/M using the specified INTERFACE.
The distance can be specified as well if desired.
@end deffn
@node Show PIM Information::
@section Show PIM Information
All PIM show commands are vrf aware and typically allow you to insert
a specified vrf command if information is desired about a specific vrf.
If no vrf is specified then the default vrf is assumed. Finally
the special keyword 'all' allows you to look at all vrfs for the command.
Naming a vrf 'all' will cause great confusion.
@deffn {Show PIM Information} {show ip multicast}
Display various information about the interfaces used in this pim
instance.
@end deffn
@deffn {Show PIM Information} {show ip mroute}
Display information about installed into the kernel S,G mroutes.
@end deffn
@deffn {Show PIM Information} {show ip mroute count}
Display information about installed into the kernel S,G mroutes
and in addition display data about packet flow for the mroutes.
@end deffn
@deffn {Show PIM Information} {show ip pim assert}
Display information about asserts in the PIM system for S,G mroutes.
@end deffn
@deffn {Show PIM Information} {show ip pim assert-internal}
Display internal assert state for S,G mroutes
@end deffn
@deffn {Show PIM Information} {show ip pim assert-metric}
Display metric information about assert state for S,G mroutes
@end deffn
@deffn {Show PIM Information} {show ip pim assert-winner-metric}
Display winner metric for assert state for S,G mroutes
@end deffn
@deffn {Show PIM Information} {show ip pim group-type}
Display SSM group ranges
@end deffn
@deffn {Show PIM Information} {show ip pim interface}
Display information about interfaces PIM is using.
@end deffn
@deffn {Show PIM Information} {show ip pim join}
Display information about PIM joins received.
@end deffn
@deffn {Show PIM Information} {show ip pim local-membership} {}
Display information about PIM interface local-membership
@end deffn
@deffn {Show PIM Information} {show ip pim neighbor} {}
Display information about PIM neighbors
@end deffn
@deffn {Show PIM Information} {show ip pim nexthop} {}
Display information about pim nexthops that are being
used
@end deffn
@deffn {Show PIM Information} {show ip pim nexthop-lookup} {}
Display information about a S,G pair and how the RPF would
be choosen. This is especially useful if there are ECMP's
available from the RPF lookup.
@end deffn
@deffn {Show PIM Information} {show ip pim rp-info} {}
Display information about RP's that are configured on
this router
@end deffn
@deffn {Show PIM Information} {show ip pim rpf} {}
Display information about currently being used S,G's
and their RPF lookup information. Additionally display
some statistics about what has been happening on the
router
@end deffn
@deffn {show PIM Information} {show ip pim secondary} {}
Display information about an interface and all the
secondary addresses associated with it
@end deffn
@deffn {show PIM Information} {show ip pim state} {}
Display information about known S,G's and incoming
interface as well as the OIL and how they were choosen
@end deffn
@deffn {show PIM Information} {show ip pim upstream} {}
Display upstream information about a S,G mroute
@end deffn
@deffn {show PIM Information} {show ip pim upstream-join-desired} {}
Display upstream information for S,G's and if we desire to
join the mcast tree
@end deffn
@deffn {show PIM Information} {show ip pim upstream-rpf} {}
Display upstream information for S,G's and the RPF data
associated with them
@end deffn
@deffn {show PIM Information} {show ip rpf} {}
Display the multicast RIB created in zebra
@end deffn
@node PIM Debug Commands
@section PIM Debug Commands
The debugging subsystem for PIM behaves in accordance with how FRR handles debugging. You can specify debugging at the enable cli mode as well as the configure cli mode. If you specify debug commands in the configuration cli mode, the debug commands can be persistent across restarts of the FRR pimd if the config was written out.
@deffn {PIM Debug Commands} {debug pim events}
This turns on debugging for PIM system events. Especially timers.
@end deffn
@deffn {PIM Debug Commands} {debug pim nht}
This turns on debugging for PIM nexthop tracking. It will display information about RPF lookups and information about when a nexthop changes.
@end deffn
@deffn {PIM Debug Commands} {debug pim packet-dump}
This turns on an extraordinary amount of data. Each pim packet sent and received is dumped for debugging purposes. This should be considered a developer only command
@end deffn
@deffn {PIM Debug Commands} {debug pim packets}
This turns on information about packet generation for sending and about packet handling from a received packet
@end deffn
@deffn {PIM Debug Commands} {debug pim trace}
This traces pim code and how it is running.
@end deffn
@deffn {PIM Debug Commands} {debug pim zebra}
This gathers data about events from zebra that come up through the zapi
@end deffn

285
doc/routemap.texi Normal file
View File

@ -0,0 +1,285 @@
@node Route Map
@chapter Route Map
Route maps provide a means to both filter and/or apply actions to
route, hence allowing policy to be applied to routes.
@menu
* Route Map Command::
* Route Map Match Command::
* Route Map Set Command::
* Route Map Call Command::
* Route Map Exit Action Command::
* Route Map Examples::
@end menu
Route-maps are an ordered list of route-map entries. Each entry may
specify up to four distincts sets of clauses:
@table @samp
@item Matching Policy
This specifies the policy implied if the @samp{Matching Conditions} are
met or not met, and which actions of the route-map are to be taken, if
any. The two possibilities are:
@itemize @minus
@item
@samp{permit}: If the entry matches, then carry out the @samp{Set
Actions}. Then finish processing the route-map, permitting the route,
unless an @samp{Exit Action} indicates otherwise.
@item
@samp{deny}: If the entry matches, then finish processing the route-map and
deny the route (return @samp{deny}).
@end itemize
The @samp{Matching Policy} is specified as part of the command which
defines the ordered entry in the route-map. See below.
@item Matching Conditions
A route-map entry may, optionally, specify one or more conditions which
must be matched if the entry is to be considered further, as governed
by the Match Policy. If a route-map entry does not explicitely specify
any matching conditions, then it always matches.
@item Set Actions
A route-map entry may, optionally, specify one or more @samp{Set
Actions} to set or modify attributes of the route.
@item Call Action
Call to another route-map, after any @samp{Set Actions} have been
carried out. If the route-map called returns @samp{deny} then
processing of the route-map finishes and the route is denied,
regardless of the @samp{Matching Policy} or the @samp{Exit Policy}. If
the called route-map returns @samp{permit}, then @samp{Matching Policy}
and @samp{Exit Policy} govern further behaviour, as normal.
@item Exit Policy
An entry may, optionally, specify an alternative @samp{Exit Policy} to
take if the entry matched, rather than the normal policy of exiting the
route-map and permitting the route. The two possibilities are:
@itemize @minus
@item
@samp{next}: Continue on with processing of the route-map entries.
@item
@samp{goto N}: Jump ahead to the first route-map entry whose order in
the route-map is >= N. Jumping to a previous entry is not permitted.
@end itemize
@end table
The default action of a route-map, if no entries match, is to deny.
I.e. a route-map essentially has as its last entry an empty @samp{deny}
entry, which matches all routes. To change this behaviour, one must
specify an empty @samp{permit} entry as the last entry in the route-map.
To summarise the above:
@multitable {permit} {action} {No Match}
@headitem @tab Match @tab No Match
@item @emph{Permit} @tab action @tab cont
@item @emph{Deny} @tab deny @tab cont
@end multitable
@table @samp
@item action
@itemize @minus
@item
Apply @emph{set} statements
@item
If @emph{call} is present, call given route-map. If that returns a @samp{deny}, finish
processing and return @samp{deny}.
@item
If @samp{Exit Policy} is @emph{next}, goto next route-map entry
@item
If @samp{Exit Policy} is @emph{goto}, goto first entry whose order in the list
is >= the given order.
@item
Finish processing the route-map and permit the route.
@end itemize
@item deny
@itemize @minus
@item
The route is denied by the route-map (return @samp{deny}).
@end itemize
@item cont
@itemize @minus
@item
goto next route-map entry
@end itemize
@end table
@node Route Map Command
@section Route Map Command
@deffn {Command} {route-map @var{route-map-name} (permit|deny) @var{order}} {}
Configure the @var{order}'th entry in @var{route-map-name} with
@samp{Match Policy} of either @emph{permit} or @emph{deny}.
@end deffn
@node Route Map Match Command
@section Route Map Match Command
@deffn {Route-map Command} {match ip address @var{access_list}} {}
Matches the specified @var{access_list}
@end deffn
@deffn {Route-map Command} {match ip address @var{prefix-list}} {}
Matches the specified @var{prefix-list}
@end deffn
@deffn {Route-map Command} {match ip address prefix-len @var{0-32}} {}
Matches the specified @var{prefix-len}. This is a Zebra specific command.
@end deffn
@deffn {Route-map Command} {match ipv6 address @var{access_list}} {}
Matches the specified @var{access_list}
@end deffn
@deffn {Route-map Command} {match ipv6 address @var{prefix-list}} {}
Matches the specified @var{prefix-list}
@end deffn
@deffn {Route-map Command} {match ipv6 address prefix-len @var{0-128}} {}
Matches the specified @var{prefix-len}. This is a Zebra specific command.
@end deffn
@deffn {Route-map Command} {match ip next-hop @var{ipv4_addr}} {}
Matches the specified @var{ipv4_addr}.
@end deffn
@deffn {Route-map Command} {match aspath @var{as_path}} {}
Matches the specified @var{as_path}.
@end deffn
@deffn {Route-map Command} {match metric @var{metric}} {}
Matches the specified @var{metric}.
@end deffn
@deffn {Route-map Command} {match tag @var{tag}} {}
Matches the specified tag value associated with the route.
This tag value can be in the range of (1-4294967295).
@end deffn
@deffn {Route-map Command} {match local-preference @var{metric}} {}
Matches the specified @var{local-preference}.
@end deffn
@deffn {Route-map Command} {match community @var{community_list}} {}
Matches the specified @var{community_list}
@end deffn
@deffn {Route-map Command} {match peer @var{ipv4_addr}} {}
This is a BGP specific match command. Matches the peer ip address
if the neighbor was specified in this manner.
@end deffn
@deffn {Route-map Command} {match peer @var{ipv6_addr}} {}
This is a BGP specific match command. Matches the peer ipv6
address if the neighbor was specified in this manner.
@end deffn
@deffn {Route-map Command} {match peer @var{interface_name}} {}
This is a BGP specific match command. Matches the peer
interface name specified if the neighbor was specified
in this manner.
@end deffn
@node Route Map Set Command
@section Route Map Set Command
@deffn {Route-map Command} {set tag @var{tag}} {}
Set a tag on the matched route. This tag value can be from
(1-4294967295). Additionally if you have compiled with
the --enable-realms configure option. Tag values from (1-255)
are sent to the linux kernel as a realm value. Then route
policy can be applied. See the tc man page.
@end deffn
@deffn {Route-map Command} {set ip next-hop @var{ipv4_address}} {}
Set the BGP nexthop address.
@end deffn
@deffn {Route-map Command} {set local-preference @var{local_pref}} {}
Set the BGP local preference to @var{local_pref}.
@end deffn
@deffn {Route-map Command} {set weight @var{weight}} {}
Set the route's weight.
@end deffn
@deffn {Route-map Command} {set metric @var{metric}} {}
@anchor{routemap set metric}
Set the BGP attribute MED.
@end deffn
@deffn {Route-map Command} {set as-path prepend @var{as_path}} {}
Set the BGP AS path to prepend.
@end deffn
@deffn {Route-map Command} {set community @var{community}} {}
Set the BGP community attribute.
@end deffn
@deffn {Route-map Command} {set ipv6 next-hop global @var{ipv6_address}} {}
Set the BGP-4+ global IPv6 nexthop address.
@end deffn
@deffn {Route-map Command} {set ipv6 next-hop local @var{ipv6_address}} {}
Set the BGP-4+ link local IPv6 nexthop address.
@end deffn
@node Route Map Call Command
@section Route Map Call Command
@deffn {Route-map Command} {call @var{name}} {}
Call route-map @var{name}. If it returns deny, deny the route and
finish processing the route-map.
@end deffn
@node Route Map Exit Action Command
@section Route Map Exit Action Command
@deffn {Route-map Command} {on-match next} {}
@deffnx {Route-map Command} {continue} {}
Proceed on to the next entry in the route-map.
@end deffn
@deffn {Route-map Command} {on-match goto @var{N}} {}
@deffnx {Route-map Command} {continue @var{N}} {}
Proceed processing the route-map at the first entry whose order is >= N
@end deffn
@node Route Map Examples
@section Route Map Examples
A simple example of a route-map:
@example
@group
route-map test permit 10
match ip address 10
set local-preference 200
@end group
@end example
This means that if a route matches ip access-list number 10 it's
local-preference value is set to 200.
See @ref{BGP Configuration Examples} for examples of more sophisticated
useage of route-maps, including of the @samp{call} action.

View File

@ -871,33 +871,19 @@ Layer protocols. BGP supports multiple Address Family Identifier (AFI), namely
IPv4 and IPv6. Support is also provided for multiple sets of per-AFI
information via Subsequent Address Family Identifiers (SAFI). In addition to
unicast information, VPN information :rfc:`4364` and :rfc:`4659`, and
Encapsulation information :rfc:`5512` is supported.
Encapsulation attribute :rfc:`5512` is supported.
.. index:: show ip bgp vpnv4 all
.. clicmd:: show ip bgp vpnv4 all
.. index:: show ip bgp ipv4 vpn
.. clicmd:: show ip bgp ipv4 vpn
.. index:: show ipv6 bgp vpn all
.. clicmd:: show ipv6 bgp vpn all
.. index:: show ipv6 bgp ipv6 vpn
.. clicmd:: show ipv6 bgp ipv6 vpn
Print active IPV4 or IPV6 routes advertised via the VPN SAFI.
.. index:: show ip bgp encap all
.. clicmd:: show ip bgp encap all
.. index:: show ipv6 bgp encap all
.. clicmd:: show ipv6 bgp encap all
Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI.
.. index:: show bgp ipv4 encap summary
.. clicmd:: show bgp ipv4 encap summary
.. index:: show bgp ipv4 vpn summary
.. clicmd:: show bgp ipv4 vpn summary
.. index:: show bgp ipv6 encap summary
.. clicmd:: show bgp ipv6 encap summary
.. index:: show bgp ipv6 vpn summary
.. clicmd:: show bgp ipv6 vpn summary

View File

@ -16,8 +16,8 @@ Both IP/Layer 3 (L3) VNs, and IP with Ethernet/Layer 2 (L2) VNs are supported.
BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VN
information between NVAs. BGP based IP VPN support is defined in :rfc:`4364`,
and :rfc:`4659`. Both the Encapsulation Subsequent Address Family Identifier
(SAFI) and the Tunnel Encapsulation Attribute, :rfc:`5512` are supported.
and :rfc:`4659`. Encapsulation information is provided via the Tunnel
Encapsulation Attribute, :rfc:`5512`.
The protocol that is used to communicate routing and Ethernet / Layer 2 (L2)
forwarding information between NVAs and NVEs is referred to as the Remote
@ -40,30 +40,26 @@ following areas:
- :dfn:`General VNC` configuration applies to general VNC operation and is
primarily used to control the method used to advertise tunnel information.
- :dfn:`Remote Forwarder Protocol (RFP)` configuration relates to the protocol
used between NVAs and NVEs.
- :dfn:`VNC Defaults` provides default parameters for registered NVEs.
- :dfn:`VNC NVE Group` provides for configuration of a specific set of
registered NVEs and overrides default parameters.
- :dfn:`Redistribution` and :dfn:`Export` control VNC-GW operation, i.e., the
import/export of routing information between VNC and customer edge routers
(:abbr:`CE`s) operating within a VN.
- :dfn:`Remote Forwarder Protocol (RFP)` configuration relates to the protocol
used between NVAs and NVEs.
- :dfn:`VNC Defaults` provides default parameters for registered NVEs.
- :dfn:`VNC NVE Group` provides for configuration of a specific set of
registered NVEs and overrides default parameters.
- :dfn:`Redistribution` and :dfn:`Export` control VNC-GW operation, i.e., the
import/export of routing information between VNC and customer edge routers
(:abbr:`CE` s) operating within a VN.
.. _General_VNC_Configuration:
.. _General_VNC_Configuration:
General VNC Configuration
-------------------------
.. General VNC Configuration
.. -------------------------
.. clicmd:: vnc advertise-un-method encap-safi|encap-attr
Advertise NVE underlay-network IP addresses using the encapsulation SAFI
(`encap-safi`) or the UN address sub-TLV of the Tunnel Encapsulation
attribute (`encap-attr`). When `encap-safi` is used, neighbors under
`address-family encap` and/or `address-family encapv6` must be configured.
The default is `encap-attr`.
.. _RFP_Related_Configuration:
.. _RFP_Related_Configuration:
RFP Related Configuration
-------------------------
@ -96,9 +92,9 @@ Enter VNC configuration mode for specifying VNC default behaviors. Use
::
vnc defaults
... various VNC defaults
exit-vnc
vnc defaults
... various VNC defaults
exit-vnc
These are the statements that can appear between ``vnc defaults`` and
@ -118,43 +114,42 @@ These are the statements that can appear between ``vnc defaults`` and
in one of the following forms:
- ``IPv4-address:two-byte-integer``
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
If no default import RT list is specified, then the default import RT list
is empty. If no default export RT list is specified, then the default export
RT list is empty.
If no default import RT list is specified, then the default import RT list
is empty. If no default export RT list is specified, then the default export
RT list is empty.
A complete definition of these parameters is given below
(:ref:`VNC_NVE_Group_Configuration`).
A complete definition of these parameters is given below
(:ref:`VNC_NVE_Group_Configuration`).
.. index:: rd route-distinguisher
.. clicmd:: rd ROUTE-DISTINGUISHER
.. index:: rd route-distinguisher
.. clicmd:: rd ROUTE-DISTINGUISHER
Specify the default route distinguisher (RD) for routes advertised via BGP
VPNs. The route distinguisher must be in one of four forms:
- ``IPv4-address:two-byte-integer``
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
- ``auto:vn:two-byte-integer``
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
- ``auto:vn:two-byte-integer``
If RD is specified in the defaults section, the default RD value is
`two-byte-autonomous-system-number=0`:`four-byte-integer=0`.
If RD is specified in the defaults section, the default RD value is
`two-byte-autonomous-system-number=0:four-byte-integer=0`.
A complete definition of this parameter is given below
(:ref:`VNC_NVE_Group_Configuration`).
A complete definition of this parameter is given below
(:ref:`VNC_NVE_Group_Configuration`).
.. index:: l2rd NVE-ID-VALUE
.. clicmd:: l2rd NVE-ID-VALUE
.. index:: l2rd NVE-ID-VALUE
.. clicmd:: l2rd NVE-ID-VALUE
Set the value used to distinguish NVEs connected to the same logical
Ethernet segment (i.e., L2VPN). A complete definition of this parameter is
given below (:ref:`VNC_NVE_Group_Configuration`).
.. index:: response-lifetime LIFETIME|infinite
.. clicmd:: response-lifetime LIFETIME|infinite
.. index:: response-lifetime LIFETIME|infinite
.. clicmd:: response-lifetime LIFETIME|infinite
Specify the default lifetime to be included in RFP response messages sent to
NVEs.
@ -163,25 +158,23 @@ These are the statements that can appear between ``vnc defaults`` and
(:ref:`VNC_NVE_Group_Configuration`).
.. index:: export bgp|zebra route-map MAP-NAME
.. clicmd:: export bgp|zebra route-map MAP-NAME
Specify that the named route-map should be applied to routes being exported
to bgp or zebra.
Specify that the named route-map should be applied to routes being exported
to bgp or zebra.
.. index:: export bgp|zebra no route-map
.. clicmd:: export bgp|zebra no route-map
Specify that no route-map should be applied to routes being exported to bgp
or zebra.
Specify that no route-map should be applied to routes being exported to bgp
or zebra.
.. index:: exit-vnc
.. clicmd:: exit-vnc
Exit VNC configuration mode.
.. _VNC_NVE_Group_Configuration:
.. _VNC_NVE_Group_Configuration:
VNC NVE Group Configuration
---------------------------
@ -210,9 +203,9 @@ Defaults section.
::
vnc nve-group group1
... configuration commands
exit-vnc
vnc nve-group group1
... configuration commands
exit-vnc
.. index:: no vnc nve-group NAME
@ -222,73 +215,73 @@ Defaults section.
The following statements are valid in an NVE group definition:
.. index:: l2rd NVE-ID-VALUE
.. clicmd:: l2rd NVE-ID-VALUE
.. index:: l2rd NVE-ID-VALUE
.. clicmd:: l2rd NVE-ID-VALUE
Set the value used to distinguish NVEs connected to the same physical
Ethernet segment (i.e., at the same location) [#]_.
Set the value used to distinguish NVEs connected to the same physical
Ethernet segment (i.e., at the same location) [#]_.
The nve-id subfield may be specified as either a literal value in the range
1-255, or it may be specified as `auto:vn`, which means to use the
least-significant octet of the originating NVE's VN address.
The nve-id subfield may be specified as either a literal value in the range
1-255, or it may be specified as `auto:vn`, which means to use the
least-significant octet of the originating NVE's VN address.
.. index:: prefix vn|un A.B.C.D/M|X:X::X:X/M
.. clicmd:: prefix vn|un A.B.C.D/M|X:X::X:X/M
Specify the matching prefix for this NVE group by either virtual-network
address (`vn`) or underlay-network address (`un`). Either or both
virtual-network and underlay-network prefixes may be specified. Subsequent
virtual-network or underlay-network values within a `vnc nve-group`
`exit-vnc` block override their respective previous values.
Specify the matching prefix for this NVE group by either virtual-network
address (`vn`) or underlay-network address (`un`). Either or both
virtual-network and underlay-network prefixes may be specified. Subsequent
virtual-network or underlay-network values within a `vnc nve-group`
`exit-vnc` block override their respective previous values.
These prefixes are used only for determining assignments of NVEs to NVE
Groups.
These prefixes are used only for determining assignments of NVEs to NVE
Groups.
.. index:: rd ROUTE-DISTINGUISHER
.. clicmd:: rd ROUTE-DISTINGUISHER
.. index:: rd ROUTE-DISTINGUISHER
.. clicmd:: rd ROUTE-DISTINGUISHER
Specify the route distinguisher for routes advertised via BGP
VPNs. The route distinguisher must be in one of these forms:
- ``IPv4-address:two-byte-integer``
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
- ``auto:vn:`two-byte-integer`
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
- ``auto:vn:`two-byte-integer`
Routes originated by NVEs in the NVE group will use the group's specified
`route-distinguisher` when they are advertised via BGP. If the `auto` form
is specified, it means that a matching NVE has its RD set to
``rd_type=IP=1:IPv4-address=VN-address:two-byte-integer``, for IPv4 VN
addresses and
``rd_type=IP=1`:`IPv4-address=Last-four-bytes-of-VN-address:two-byte-integer``,
for IPv6 VN addresses.
Routes originated by NVEs in the NVE group will use the group's specified
`route-distinguisher` when they are advertised via BGP. If the `auto` form
is specified, it means that a matching NVE has its RD set to
``rd_type=IP=1:IPv4-address=VN-address:two-byte-integer``, for IPv4 VN
addresses and
``rd_type=IP=1:IPv4-address=Last-four-bytes-of-VN-address:two-byte-integer``,
for IPv6 VN addresses.
If the NVE group definition does not specify a `route-distinguisher`, then
the default `route-distinguisher` is used. If neither a group nor a default
`route-distinguisher` is configured, then the advertised RD is set to
``two-byte-autonomous-system-number=0:four-byte-integer=0``.
If the NVE group definition does not specify a `route-distinguisher`, then
the default `route-distinguisher` is used. If neither a group nor a default
`route-distinguisher` is configured, then the advertised RD is set to
``two-byte-autonomous-system-number=0:four-byte-integer=0``.
.. index:: response-lifetime LIFETIME|infinite
.. clicmd:: response-lifetime LIFETIME|infinite
.. index:: response-lifetime LIFETIME|infinite
.. clicmd:: response-lifetime LIFETIME|infinite
Specify the response lifetime, in seconds, to be included in RFP response
messages sent to NVEs. If the value 'infinite' is given, an infinite
lifetime will be used.
Specify the response lifetime, in seconds, to be included in RFP response
messages sent to NVEs. If the value 'infinite' is given, an infinite
lifetime will be used.
Note that this parameter is not the same as the lifetime supplied by NVEs in
RFP registration messages. This parameter does not affect the lifetime value
attached to routes sent by this server via BGP.
Note that this parameter is not the same as the lifetime supplied by NVEs in
RFP registration messages. This parameter does not affect the lifetime value
attached to routes sent by this server via BGP.
If the NVE group definition does not specify a `response-lifetime`, the
default `response-lifetime` will be used. If neither a group nor a default
`response-lifetime` is configured, the value 3600 will be used. The maximum
response lifetime is 2147483647.
If the NVE group definition does not specify a `response-lifetime`, the
default `response-lifetime` will be used. If neither a group nor a default
`response-lifetime` is configured, the value 3600 will be used. The maximum
response lifetime is 2147483647.
.. index:: rt export RT-LIST
.. clicmd:: rt export RT-LIST
.. index:: rt export RT-LIST
.. clicmd:: rt export RT-LIST
.. index:: rt import RT-LIST
.. clicmd:: rt import RT-LIST
.. index:: rt import RT-LIST
.. clicmd:: rt import RT-LIST
.. index:: rt both RT-LIST
.. clicmd:: rt both RT-LIST
@ -297,9 +290,9 @@ least-significant octet of the originating NVE's VN address.
space-separated list of route targets, each element of which is
in one of the following forms:
``IPv4-address:two-byte-integer``
``four-byte-autonomous-system-number:two-byte-integer``
``two-byte-autonomous-system-number:four-byte-integer``
- ``IPv4-address:two-byte-integer``
- ``four-byte-autonomous-system-number:two-byte-integer``
- ``two-byte-autonomous-system-number:four-byte-integer``
The first form, `rt export`, specifies an `export rt-list`. The `export
rt-list` will be attached to routes originated by NVEs in the NVE group
@ -311,8 +304,7 @@ least-significant octet of the originating NVE's VN address.
The second form, `rt import` specifies an `import rt-list`, which is a
filter for incoming routes. In order to be made available to NVEs in the
group, incoming BGP VPN and `ENCAP` `SAFI` (when `vnc advertise-un-method
encap-safi` is set) routes must have RT lists that have at least one
group, incoming BGP VPN routes must have RT lists that have at least one
route target in common with the group's `import rt-list`.
If the NVE group definition does not specify an import filter, then the
@ -560,7 +552,6 @@ Redistribution Command Syntax
.. index:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
.. clicmd:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
Import (or do not import) prefixes from another routing protocols. Specify
both the address family to import (`ipv4` or `ipv6`) and the protocol
(`bgp`, `bgp-direct`, `bgp-direct-to-nve-groups`, `connected`, `kernel`,
@ -573,7 +564,6 @@ Redistribution Command Syntax
.. index:: vnc redistribute mode plain|nve-group|resolve-nve
.. clicmd:: vnc redistribute mode plain|nve-group|resolve-nve
Redistribute routes from other protocols into VNC using the specified mode.
Not all combinations of modes and protocols are supported.
@ -583,7 +573,6 @@ Redistribution Command Syntax
.. index:: no vnc redistribute nve-group GROUP-NAME
.. clicmd:: no vnc redistribute nve-group GROUP-NAME
When using `nve-group` mode, assign (or do not assign) the NVE group
`group-name` to routes redistributed from another routing protocol.
`group-name` must be configured using `vnc nve-group`.
@ -595,7 +584,6 @@ Redistribution Command Syntax
.. index:: vnc redistribute lifetime LIFETIME|infinite
.. clicmd:: vnc redistribute lifetime LIFETIME|infinite
Assign a registration lifetime, either `lifetime` seconds or `infinite`, to
prefixes redistributed from other routing protocols as if they had been
received via RFP registration messages from an NVE. `lifetime` can be any
@ -604,7 +592,6 @@ Redistribution Command Syntax
.. index:: vnc redistribute resolve-nve roo-ec-local-admin 0-65536
.. clicmd:: vnc redistribute resolve-nve roo-ec-local-admin 0-65536
Assign a value to the local-administrator subfield used in the
Route Origin extended community that is assigned to routes exported
under the `resolve-nve` mode. The default value is `5226`.
@ -657,7 +644,6 @@ a corresponding `redistribute vnc-direct` statement.
.. index:: export bgp|zebra mode none|group-nve|registering-nve|ce
.. clicmd:: export bgp|zebra mode none|group-nve|registering-nve|ce
Specify how routes should be exported to bgp or zebra. If the mode is
`none`, routes are not exported. If the mode is `group-nve`, routes are
exported according to nve-group or vrf-policy group configuration
@ -671,7 +657,7 @@ a corresponding `redistribute vnc-direct` statement.
The next hop of the exported route is set to the encoded NVE connected CE
Router.
The default for both bgp and zebra is mode `none`.
The default for both bgp and zebra is mode `none`.
.. index:: vnc export bgp|zebra group-nve group GROUP-NAME
.. clicmd:: vnc export bgp|zebra group-nve group GROUP-NAME
@ -697,14 +683,13 @@ a corresponding `redistribute vnc-direct` statement.
.. index:: export bgp|zebra no ipv4|ipv6 prefix-list
.. clicmd:: export bgp|zebra no ipv4|ipv6 prefix-list
When export mode is `ce` or `registering-nve`,
specifies that no prefix-list should be applied to routes
being exported to bgp or zebra.
When export mode is `ce` or `registering-nve`,
specifies that no prefix-list should be applied to routes
being exported to bgp or zebra.
.. index:: export bgp|zebra route-map MAP-NAME
.. clicmd:: export bgp|zebra route-map MAP-NAME
When export mode is `ce` or `registering-nve`, specifies that the named
route-map should be applied to routes being exported to bgp or zebra.
@ -903,7 +888,6 @@ related information:
.. index:: show memory vnc
.. clicmd:: show memory vnc
Print the number of memory items allocated by the NVA.
.. _Example_VNC_and_VNC-GW_Configurations:
@ -911,6 +895,606 @@ related information:
Example VNC and VNC-GW Configurations
=====================================
.. _vnc-mesh-nva-config:
Mesh NVA Configuration
----------------------
This example includes three NVAs, nine NVEs, and two NVE groups. Note that
while not shown, a single physical device may support multiple logical NVEs.
:figure:`fig-vnc-mesh` shows ``code NVA-1`` (192.168.1.100), ``NVA 2``
(192.168.1.101), and ``NVA 3`` (192.168.1.102), which are connected in a full
mesh. Each is a member of the autonomous system 64512. Each NVA provides VNC
services to three NVE clients in the 172.16.0.0/16 virtual-network address
range. The 172.16.0.0/16 address range is partitioned into two NVE groups,
``group1`` (172.16.0.0/17) and ``group2`` (172.16.128.0/17).
Each NVE belongs to either NVE group ``group1`` or NVE group
``group2``. The NVEs ``NVE 1``, ``NVE 2``, @code{NVE
4}, ``NVE 7``, and ``NVE 8`` are members of the NVE group
``group1``. The NVEs ``NVE 3``, ``NVE 5``, @code{NVE
6}, and ``NVE 9`` are members of the NVE group ``group2``.
Each NVA advertises NVE underlay-network IP addresses using the
Tunnel Encapsulation Attribute.
.. _vnc-fig-vnc-mesh:
.. figure:: ../figure/fig-vnc-mesh.png
:align: center
:alt: Three-way Mesh
A three-way full mesh with three NVEs per NVA.
:file:`bgpd.conf` for ``NVA 1`` (192.168.1.100):::
router bgp 64512
bgp router-id 192.168.1.100
neighbor 192.168.1.101 remote-as 64512
neighbor 192.168.1.102 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.101 activate
neighbor 192.168.1.102 activate
exit-address-family
vnc defaults
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
vnc nve-group group1
prefix vn 172.16.0.0/17
rt both 1000:1
exit-vnc
vnc nve-group group2
prefix vn 172.16.128.0/17
rt both 1000:2
exit-vnc
exit
:file:`bgpd.conf` for ``NVA 2`` (192.168.1.101):::
router bgp 64512
bgp router-id 192.168.1.101
neighbor 192.168.1.100 remote-as 64512
neighbor 192.168.1.102 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
neighbor 192.168.1.102 activate
exit-address-family
vnc nve-group group1
prefix vn 172.16.0.0/17
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
exit
:file:`bgpd.conf` for ``NVA 3`` (192.168.1.102):::
router bgp 64512
bgp router-id 192.168.1.102
neighbor 192.168.1.101 remote-as 64512
neighbor 192.168.1.102 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
neighbor 192.168.1.101 activate
exit-address-family
vnc defaults
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
vnc nve-group group1
prefix vn 172.16.128.0/17
exit-vnc
exit
Mesh NVA and VNC-GW Configuration
---------------------------------
This example includes two NVAs, each with two associated NVEs, and two VNC-GWs,
each supporting two CE routers physically attached to the four NVEs. Note that
this example is showing a more complex configuration where VNC-GW is separated
from normal NVA functions; it is equally possible to simplify the configuration
and combine NVA and VNC-GW functions in a single FRR instance.
.. _vnc-fig-vnc-gw:
.. figure:: ../figures/fig-vnc-gw.png
:align: center
:alt: FRR VNC Gateway
Meshed NVEs and VNC-GWs
As shown in :figure:`fig-vnc-gw`, NVAs and VNC-GWs are connected in a full iBGP
mesh. The VNC-GWs each have two CEs configured as route-reflector clients.
Each client provides BGP updates with unicast routes that the VNC-GW reflects
to the other client. The VNC-GW also imports these unicast routes into VPN
routes to be shared with the other VNC-GW and the two NVAs. This route
importation is controlled with the ``vnc redistribute`` statements shown in the
configuration. Similarly, registrations sent by NVEs via RFP to the NVAs are
exported by the VNC-GWs to the route-reflector clients as unicast routes. RFP
registrations exported this way have a next-hop address of the CE behind the
connected (registering) NVE. Exporting VNC routes as IPv4 unicast is enabled
with the ``vnc export`` command below.
The configuration for ``VNC-GW 1`` is shown below.::
router bgp 64512
bgp router-id 192.168.1.101
bgp cluster-id 1.2.3.4
neighbor 192.168.1.102 remote-as 64512
neighbor 192.168.1.103 remote-as 64512
neighbor 192.168.1.104 remote-as 64512
neighbor 172.16.1.2 remote-as 64512
neighbor 172.16.2.2 remote-as 64512
!
address-family ipv4 unicast
redistribute vnc-direct
no neighbor 192.168.1.102 activate
no neighbor 192.168.1.103 activate
no neighbor 192.168.1.104 activate
neighbor 172.16.1.2 route-reflector-client
neighbor 172.16.2.2 route-reflector-client
exit-address-family
!
address-family ipv4 vpn
neighbor 192.168.1.102 activate
neighbor 192.168.1.103 activate
neighbor 192.168.1.104 activate
exit-address-family
vnc export bgp mode ce
vnc redistribute mode resolve-nve
vnc redistribute ipv4 bgp-direct
exit
Note that in the VNC-GW configuration, the neighboring VNC-GW and NVAs each
have a statement disabling the IPv4 unicast address family. IPv4 unicast is on
by default and this prevents the other VNC-GW and NVAs from learning unicast
routes advertised by the route-reflector clients.
Configuration for ``NVA 2``:::
router bgp 64512
bgp router-id 192.168.1.104
neighbor 192.168.1.101 remote-as 64512
neighbor 192.168.1.102 remote-as 64512
neighbor 192.168.1.103 remote-as 64512
!
address-family ipv4 unicast
no neighbor 192.168.1.101 activate
no neighbor 192.168.1.102 activate
no neighbor 192.168.1.103 activate
exit-address-family
!
address-family ipv4 vpn
neighbor 192.168.1.101 activate
neighbor 192.168.1.102 activate
neighbor 192.168.1.103 activate
exit-address-family
!
vnc defaults
response-lifetime 3600
exit-vnc
vnc nve-group nve1
prefix vn 172.16.1.1/32
response-lifetime 3600
rt both 1000:1 1000:2
exit-vnc
vnc nve-group nve2
prefix vn 172.16.2.1/32
response-lifetime 3600
rt both 1000:1 1000:2
exit-vnc
exit
.. TBD make this its own example:
..
.. @float Figure,fig:fig-vnc-gw-rr
.. @center @image{fig-vnc-gw-rr,400pt,,Frr VNC Gateway with RR}
.. @end float
.. An NVA can also import unicast routes from BGP without advertising the
.. imported routes as VPN routes. Such imported routes, while not
.. distributed to other NVAs or VNC-GWs, are are available to NVEs via
.. RFP query messages sent to the NVA. @ref{fig:fig-vnc-gw-rr}
.. shows an example topology where unicast routes are imported into NVAs
.. from a Route Reflector. (@pxref{Route Reflector} for route reflector
.. configuration details.) The following three lines can be added to the
.. ``NVA 1`` and ``NVA 2`` configurations to import routes into VNC
.. for local VNC use:
..
.. @verbatim
.. neighbor 192.168.1.105 remote-as 64512
.. vnc redistribute mode plain
.. vnc redistribute ipv4 bgp-direct-to-nve-groups
.. @end verbatim
.. _vnc-with-frr-route-reflector-config:
VNC with FRR Route Reflector Configuration
------------------------------------------
A route reflector eliminates the need for a fully meshed NVA network by acting
as the hub between NVAs. :figure:`vnc-fig-vnc-frr-route-reflector` shows BGP
route reflector ``BGP Route Reflector 1`` (192.168.1.100) as a route reflector
for NVAs ``NVA 2``(192.168.1.101) and ``NVA 3`` (192.168.1.102).
@float Figure,fig:fig-vnc-frr-route-reflector @center
@image{fig-vnc-frr-route-reflector,400pt,,Frr Route Reflector} @caption{Two
NVAs and a BGP Route Reflector} @end float
.. _vnc-fig-vnc-frr-route-reflector:
.. figure:: ../figures/fig-vnc-frr-route-reflector.png
:align: center
:alt: FRR Route Reflector
Two NVAs and a BGP Route Reflector
``NVA 2`` and ``NVA 3`` advertise NVE underlay-network IP addresses using the
Tunnel Encapsulation Attribute. ``BGP Route Reflector 1`` ``reflects''
advertisements from ``NVA 2`` to ``NVA 3`` and vice versa.
As in the example of :ref:`vnc-mesh-nva-config`, there are two NVE groups. The
172.16.0.0/16 address range is partitioned into two NVE groups, ``group1``
(172.16.0.0/17) and ``group2`` (172.16.128.0/17). The NVE ``NVE 4``, ``NVE
7``, and ``NVE 8`` are members of the NVE group ``group1``. The NVEs ``NVE
5``, ``NVE 6``, and ``NVE 9`` are members of the NVE group ``group2``.
:file:`bgpd.conf` for ``BGP Route Reflector 1`` on 192.168.1.100:::
router bgp 64512
bgp router-id 192.168.1.100
neighbor 192.168.1.101 remote-as 64512
neighbor 192.168.1.101 port 7179
neighbor 192.168.1.101 description iBGP-client-192-168-1-101
neighbor 192.168.1.102 remote-as 64512
neighbor 192.168.1.102 port 7179
neighbor 192.168.1.102 description iBGP-client-192-168-1-102
address-family ipv4 unicast
neighbor 192.168.1.101 route-reflector-client
neighbor 192.168.1.102 route-reflector-client
exit-address-family
address-family ipv4 vpn
neighbor 192.168.1.101 activate
neighbor 192.168.1.102 activate
neighbor 192.168.1.101 route-reflector-client
neighbor 192.168.1.102 route-reflector-client
exit-address-family
exit
:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
router bgp 64512
bgp router-id 192.168.1.101
neighbor 192.168.1.100 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
exit-address-family
vnc nve-group group1
prefix vn 172.16.0.0/17
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
exit
:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.102:::
router bgp 64512
bgp router-id 192.168.1.102
neighbor 192.168.1.100 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
exit-address-family
vnc defaults
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
vnc nve-group group1
prefix vn 172.16.128.0/17
exit-vnc
exit
While not shown, an NVA can also be configured as a route reflector.
.. _vnc-with-commercial-route-reflector-config:
VNC with Commercial Route Reflector Configuration
-------------------------------------------------
This example is identical to :ref:`vnc-with-frr-route-reflector-configuration`
with the exception that the route reflector is a commercial router. Only the
VNC-relevant configuration is provided.
.. figure:: ../figures/fig-vnc-commercial-route-reflector
:align: center
:alt: Commercial Route Reflector
Two NVAs with a commercial route reflector
:file:`bgpd.conf` for BGP route reflector ``Commercial Router`` on 192.168.1.104:::
version 8.5R1.13;
routing-options {
rib inet.0 {
static {
route 172.16.0.0/16 next-hop 192.168.1.104;
}
}
autonomous-system 64512;
resolution {
rib inet.3 {
resolution-ribs inet.0;
}
rib bgp.l3vpn.0 {
resolution-ribs inet.0;
}
}
}
protocols {
bgp {
advertise-inactive;
family inet {
labeled-unicast;
}
group 1 {
type internal;
advertise-inactive;
advertise-peer-as;
import h;
family inet {
unicast;
}
family inet-vpn {
unicast;
}
cluster 192.168.1.104;
neighbor 192.168.1.101;
neighbor 192.168.1.102;
}
}
}
policy-options {
policy-statement h {
from protocol bgp;
then {
as-path-prepend 64512;
accept;
}
}
}
:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
router bgp 64512
bgp router-id 192.168.1.101
neighbor 192.168.1.100 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
exit-address-family
vnc nve-group group1
prefix vn 172.16.0.0/17
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
exit
:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:::
router bgp 64512
bgp router-id 192.168.1.102
neighbor 192.168.1.100 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
exit-address-family
vnc defaults
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
vnc nve-group group1
prefix vn 172.16.128.0/17
exit-vnc
exit
VNC with Redundant Route Reflectors Configuration
-------------------------------------------------
This example combines the previous two
(:ref:`vnc-with-frr-route-reflector-config` and
:ref:`vnc-with-commercial-route-reflector-config`) into a redundant route
reflector configuration. BGP route reflectors ``BGP Route Reflector 1`` and
``Commercial Router`` are the route reflectors for NVAs ``NVA 2`` and ``NVA
3``. The two NVAs have connections to both route reflectors.
.. figure:: ../fig-vnc-redundant-route-reflectors.png
:align: center
:alt: Redundant Route Reflectors
FRR-based NVA with redundant route reflectors
:file:`bgpd.conf` for ``Bgpd Route Reflector 1`` on 192.168.1.100:::
router bgp 64512
bgp router-id 192.168.1.100
bgp cluster-id 192.168.1.100
neighbor 192.168.1.104 remote-as 64512
neighbor 192.168.1.101 remote-as 64512
neighbor 192.168.1.101 description iBGP-client-192-168-1-101
neighbor 192.168.1.101 route-reflector-client
neighbor 192.168.1.102 remote-as 64512
neighbor 192.168.1.102 description iBGP-client-192-168-1-102
neighbor 192.168.1.102 route-reflector-client
address-family ipv4 vpn
neighbor 192.168.1.101 activate
neighbor 192.168.1.102 activate
neighbor 192.168.1.104 activate
neighbor 192.168.1.101 route-reflector-client
neighbor 192.168.1.102 route-reflector-client
exit-address-family
exit
:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
router bgp 64512
bgp router-id 192.168.1.101
neighbor 192.168.1.100 remote-as 64512
neighbor 192.168.1.104 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
neighbor 192.168.1.104 activate
exit-address-family
vnc nve-group group1
prefix vn 172.16.0.0/17
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
exit
:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:::
router bgp 64512
bgp router-id 192.168.1.102
neighbor 192.168.1.100 remote-as 64512
neighbor 192.168.1.104 remote-as 64512
address-family ipv4 vpn
neighbor 192.168.1.100 activate
neighbor 192.168.1.104 activate
exit-address-family
vnc defaults
rd 64512:1
response-lifetime 200
rt both 1000:1 1000:2
exit-vnc
vnc nve-group group1
prefix vn 172.16.128.0/17
exit-vnc
exit
:file:`bgpd.conf` for the Commercial Router route reflector on 192.168.1.104:::
routing-options {
rib inet.0 {
static {
route 172.16.0.0/16 next-hop 192.168.1.104;
}
}
autonomous-system 64512;
resolution {
rib inet.3 {
resolution-ribs inet.0;
}
rib bgp.l3vpn.0 {
resolution-ribs inet.0;
}
}
}
protocols {
bgp {
advertise-inactive;
family inet {
labeled-unicast;
}
group 1 {
type internal;
advertise-inactive;
advertise-peer-as;
import h;
family inet {
unicast;
}
family inet-vpn {
unicast;
}
cluster 192.168.1.104;
neighbor 192.168.1.101;
neighbor 192.168.1.102;
}
group 2 {
type internal;
advertise-inactive;
advertise-peer-as;
import h;
family inet {
unicast;
}
family inet-vpn {
unicast;
}
neighbor 192.168.1.100;
}
}
}
policy-options {
policy-statement h {
from protocol bgp;
then {
as-path-prepend 64512;
accept;
}
}
}
.. [#] The nve-id is carriedin the route distinguisher. It is the second octet
of the eight-octet route distinguisher generated for Ethernet / L2
advertisements. The first octet is a constant 0xFF, and the third

1593
doc/vnc.texi Normal file

File diff suppressed because it is too large Load Diff

View File

@ -170,9 +170,11 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
*/
if (!dest) {
char buf[PREFIX_STRLEN];
zlog_err("%s: Received prefix %s which we do not know about",
__PRETTY_FUNCTION__,
prefix2str(&dest_addr, buf, strlen(buf)));
prefix2str(&dest_addr, buf, sizeof(buf)));
eigrp_IPv4_InternalTLV_free(tlv);
continue;
}

View File

@ -366,6 +366,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.nh_vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_EIGRP;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));
@ -407,6 +408,7 @@ void eigrp_zebra_route_delete(struct prefix *p)
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.nh_vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_EIGRP;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));

View File

@ -14,8 +14,6 @@
* into proprietary software; there is no requirement for such software to
* contain a copyright notice related to this source.
*
* $Id: dict.h,v 1.3 2005/09/25 12:04:25 hasso Exp $
* $Name: $
*/
#ifndef DICT_H

View File

@ -46,15 +46,14 @@
#include "privs.h"
struct bpf_insn llcfilter[] = {
/* check first byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN),
BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
ETHER_HDR_LEN), /* check first byte */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
/* check second byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 1),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3),
/* check third byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 2),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1),
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0,
3), /* check second byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */
BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
BPF_STMT(BPF_RET + BPF_K, 0)};
u_int readblen = 0;
@ -242,14 +241,15 @@ int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa)
assert(bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETH_ALEN;
offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
/* then we lose the BPF, LLC and ethernet headers */
stream_write(circuit->rcv_stream, readbuff + offset,
bpf_hdr->bh_caplen - LLC_LEN - ETH_ALEN);
bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
stream_set_getp(circuit->rcv_stream, 0);
memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, ETH_ALEN);
memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN,
ETH_ALEN);
if (ioctl(circuit->fd, BIOCFLUSH, &one) < 0)
zlog_warn("Flushing failed: %s", safe_strerror(errno));
@ -263,7 +263,7 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
ssize_t written;
size_t buflen;
buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETH_ALEN;
buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
if (buflen > sizeof(sock_buff)) {
zlog_warn(
"isis_send_pdu_bcast: sock_buff size %zu is less than "
@ -289,12 +289,12 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
/*
* Then the LLC
*/
sock_buff[ETH_ALEN] = ISO_SAP;
sock_buff[ETH_ALEN + 1] = ISO_SAP;
sock_buff[ETH_ALEN + 2] = 0x03;
sock_buff[ETHER_HDR_LEN] = ISO_SAP;
sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
sock_buff[ETHER_HDR_LEN + 2] = 0x03;
/* then we copy the data */
memcpy(sock_buff + (LLC_LEN + ETH_ALEN), circuit->snd_stream->data,
memcpy(sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
stream_get_endp(circuit->snd_stream));
/* now we can send this */

View File

@ -676,7 +676,8 @@ int isis_circuit_up(struct isis_circuit *circuit)
circuit->lsp_queue = list_new();
circuit->lsp_hash = isis_lsp_hash_new();
circuit->lsp_queue_last_push = monotime(NULL);
circuit->lsp_queue_last_push[0] = circuit->lsp_queue_last_push[1] =
monotime(NULL);
return ISIS_OK;
}

View File

@ -84,7 +84,7 @@ struct isis_circuit {
struct thread *t_send_lsp;
struct list *lsp_queue; /* LSPs to be txed (both levels) */
struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */
time_t lsp_queue_last_push; /* timestamp used to enforce transmit
time_t lsp_queue_last_push[2]; /* timestamp used to enforce transmit
* interval;
* for scalability, use one timestamp per
* circuit, instead of one per lsp per

View File

@ -1873,12 +1873,12 @@ int lsp_tick(struct thread *thread)
if (!circuit->lsp_queue)
continue;
if (now - circuit->lsp_queue_last_push
if (now - circuit->lsp_queue_last_push[level]
< MIN_LSP_RETRANS_INTERVAL) {
continue;
}
circuit->lsp_queue_last_push = now;
circuit->lsp_queue_last_push[level] = now;
for (ALL_LIST_ELEMENTS_RO(
lsp_list, lspnode, lsp)) {

View File

@ -1249,7 +1249,7 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level,
}
static int isis_run_spf(struct isis_area *area, int level, int family,
u_char *sysid)
u_char *sysid, struct timeval *nowtv)
{
int retval = ISIS_OK;
struct isis_vertex *vertex;
@ -1263,9 +1263,8 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
uint16_t mtid;
/* Get time that can't roll backwards. */
monotime(&time_now);
start_time = time_now.tv_sec;
start_time = (start_time * 1000000) + time_now.tv_usec;
start_time = nowtv->tv_sec;
start_time = (start_time * 1000000) + nowtv->tv_usec;
if (family == AF_INET)
spftree = area->spftree[level - 1];
@ -1372,9 +1371,11 @@ static int isis_run_spf_cb(struct thread *thread)
area->area_tag, level);
if (area->ip_circuits)
retval = isis_run_spf(area, level, AF_INET, isis->sysid);
retval = isis_run_spf(area, level, AF_INET, isis->sysid,
&thread->real);
if (area->ipv6_circuits)
retval = isis_run_spf(area, level, AF_INET6, isis->sysid);
retval = isis_run_spf(area, level, AF_INET6, isis->sysid,
&thread->real);
return retval;
}
@ -1435,9 +1436,8 @@ int isis_spf_schedule(struct isis_area *area, int level)
timer, &area->spf_timer[level - 1]);
if (isis->debugs & DEBUG_SPF_EVENTS)
zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
area->area_tag, level,
area->min_spf_interval[level - 1] - diff);
zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %ld sec from now",
area->area_tag, level, timer);
return ISIS_OK;
}

View File

@ -261,6 +261,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.nh_vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
@ -329,6 +330,7 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.nh_vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;

View File

@ -47,58 +47,58 @@ ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
if (dir_str[0] == 'r') {
if (negate)
DEBUG_OFF(hello, HELLO_RECV);
DEBUG_OFF(hello, LDP_DEBUG_HELLO_RECV);
else
DEBUG_ON(hello, HELLO_RECV);
DEBUG_ON(hello, LDP_DEBUG_HELLO_RECV);
} else {
if (negate)
DEBUG_OFF(hello, HELLO_SEND);
DEBUG_OFF(hello, LDP_DEBUG_HELLO_SEND);
else
DEBUG_ON(hello, HELLO_SEND);
DEBUG_ON(hello, LDP_DEBUG_HELLO_SEND);
}
} else if (strcmp(type_str, "errors") == 0) {
if (negate)
DEBUG_OFF(errors, ERRORS);
DEBUG_OFF(errors, LDP_DEBUG_ERRORS);
else
DEBUG_ON(errors, ERRORS);
DEBUG_ON(errors, LDP_DEBUG_ERRORS);
} else if (strcmp(type_str, "event") == 0) {
if (negate)
DEBUG_OFF(event, EVENT);
DEBUG_OFF(event, LDP_DEBUG_EVENT);
else
DEBUG_ON(event, EVENT);
DEBUG_ON(event, LDP_DEBUG_EVENT);
} else if (strcmp(type_str, "labels") == 0) {
if (negate)
DEBUG_OFF(labels, LABELS);
DEBUG_OFF(labels, LDP_DEBUG_LABELS);
else
DEBUG_ON(labels, LABELS);
DEBUG_ON(labels, LDP_DEBUG_LABELS);
} else if (strcmp(type_str, "messages") == 0) {
if (dir_str == NULL)
return (CMD_WARNING_CONFIG_FAILED);
if (dir_str[0] == 'r') {
if (negate) {
DEBUG_OFF(msg, MSG_RECV);
DEBUG_OFF(msg, MSG_RECV_ALL);
DEBUG_OFF(msg, LDP_DEBUG_MSG_RECV);
DEBUG_OFF(msg, LDP_DEBUG_MSG_RECV_ALL);
} else {
DEBUG_ON(msg, MSG_RECV);
DEBUG_ON(msg, LDP_DEBUG_MSG_RECV);
if (all)
DEBUG_ON(msg, MSG_RECV_ALL);
DEBUG_ON(msg, LDP_DEBUG_MSG_RECV_ALL);
}
} else {
if (negate) {
DEBUG_OFF(msg, MSG_SEND);
DEBUG_OFF(msg, MSG_SEND_ALL);
DEBUG_OFF(msg, LDP_DEBUG_MSG_SEND);
DEBUG_OFF(msg, LDP_DEBUG_MSG_SEND_ALL);
} else {
DEBUG_ON(msg, MSG_SEND);
DEBUG_ON(msg, LDP_DEBUG_MSG_SEND);
if (all)
DEBUG_ON(msg, MSG_SEND_ALL);
DEBUG_ON(msg, LDP_DEBUG_MSG_SEND_ALL);
}
}
} else if (strcmp(type_str, "zebra") == 0) {
if (negate)
DEBUG_OFF(zebra, ZEBRA);
DEBUG_OFF(zebra, LDP_DEBUG_ZEBRA);
else
DEBUG_ON(zebra, ZEBRA);
DEBUG_ON(zebra, LDP_DEBUG_ZEBRA);
}
main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
@ -112,27 +112,27 @@ ldp_vty_show_debugging(struct vty *vty)
{
vty_out (vty, "LDP debugging status:\n");
if (LDP_DEBUG(hello, HELLO_RECV))
if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_RECV))
vty_out (vty," LDP discovery debugging is on (inbound)\n");
if (LDP_DEBUG(hello, HELLO_SEND))
if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_SEND))
vty_out (vty," LDP discovery debugging is on (outbound)\n");
if (LDP_DEBUG(errors, ERRORS))
if (LDP_DEBUG(errors, LDP_DEBUG_ERRORS))
vty_out (vty, " LDP errors debugging is on\n");
if (LDP_DEBUG(event, EVENT))
if (LDP_DEBUG(event, LDP_DEBUG_EVENT))
vty_out (vty, " LDP events debugging is on\n");
if (LDP_DEBUG(labels, LABELS))
if (LDP_DEBUG(labels, LDP_DEBUG_LABELS))
vty_out (vty, " LDP labels debugging is on\n");
if (LDP_DEBUG(msg, MSG_RECV_ALL))
if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV_ALL))
vty_out (vty,
" LDP detailed messages debugging is on (inbound)\n");
else if (LDP_DEBUG(msg, MSG_RECV))
else if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV))
vty_out (vty," LDP messages debugging is on (inbound)\n");
if (LDP_DEBUG(msg, MSG_SEND_ALL))
if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND_ALL))
vty_out (vty,
" LDP detailed messages debugging is on (outbound)\n");
else if (LDP_DEBUG(msg, MSG_SEND))
else if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND))
vty_out (vty," LDP messages debugging is on (outbound)\n");
if (LDP_DEBUG(zebra, ZEBRA))
if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA))
vty_out (vty, " LDP zebra debugging is on\n");
vty_out (vty, "\n");
@ -144,48 +144,48 @@ ldp_debug_config_write(struct vty *vty)
{
int write = 0;
if (CONF_LDP_DEBUG(hello, HELLO_RECV)) {
if (CONF_LDP_DEBUG(hello, LDP_DEBUG_HELLO_RECV)) {
vty_out (vty,"debug mpls ldp discovery hello recv\n");
write = 1;
}
if (CONF_LDP_DEBUG(hello, HELLO_SEND)) {
if (CONF_LDP_DEBUG(hello, LDP_DEBUG_HELLO_SEND)) {
vty_out (vty,"debug mpls ldp discovery hello sent\n");
write = 1;
}
if (CONF_LDP_DEBUG(errors, ERRORS)) {
if (CONF_LDP_DEBUG(errors, LDP_DEBUG_ERRORS)) {
vty_out (vty, "debug mpls ldp errors\n");
write = 1;
}
if (CONF_LDP_DEBUG(event, EVENT)) {
if (CONF_LDP_DEBUG(event, LDP_DEBUG_EVENT)) {
vty_out (vty, "debug mpls ldp event\n");
write = 1;
}
if (CONF_LDP_DEBUG(labels, LABELS)) {
if (CONF_LDP_DEBUG(labels, LDP_DEBUG_LABELS)) {
vty_out (vty, "debug mpls ldp labels\n");
write = 1;
}
if (CONF_LDP_DEBUG(msg, MSG_RECV_ALL)) {
if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV_ALL)) {
vty_out (vty, "debug mpls ldp messages recv all\n");
write = 1;
} else if (CONF_LDP_DEBUG(msg, MSG_RECV)) {
} else if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV)) {
vty_out (vty, "debug mpls ldp messages recv\n");
write = 1;
}
if (CONF_LDP_DEBUG(msg, MSG_SEND_ALL)) {
if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND_ALL)) {
vty_out (vty, "debug mpls ldp messages sent all\n");
write = 1;
} else if (CONF_LDP_DEBUG(msg, MSG_SEND)) {
} else if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND)) {
vty_out (vty, "debug mpls ldp messages sent\n");
write = 1;
}
if (CONF_LDP_DEBUG(zebra, ZEBRA)) {
if (CONF_LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA)) {
vty_out (vty, "debug mpls ldp zebra\n");
write = 1;
}

View File

@ -46,11 +46,11 @@ struct ldp_debug {
extern struct ldp_debug conf_ldp_debug;
extern struct ldp_debug ldp_debug;
#define CONF_DEBUG_ON(a, b) (conf_ldp_debug.a |= (LDP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_ldp_debug.a &= ~(LDP_DEBUG_ ## b))
#define CONF_DEBUG_ON(a, b) (conf_ldp_debug.a |= (b))
#define CONF_DEBUG_OFF(a, b) (conf_ldp_debug.a &= ~(b))
#define TERM_DEBUG_ON(a, b) (ldp_debug.a |= (LDP_DEBUG_ ## b))
#define TERM_DEBUG_OFF(a, b) (ldp_debug.a &= ~(LDP_DEBUG_ ## b))
#define TERM_DEBUG_ON(a, b) (ldp_debug.a |= (b))
#define TERM_DEBUG_OFF(a, b) (ldp_debug.a &= ~(b))
#define DEBUG_ON(a, b) \
do { \
@ -66,48 +66,48 @@ extern struct ldp_debug ldp_debug;
TERM_DEBUG_OFF(a, b); \
} while (0)
#define LDP_DEBUG(a, b) (ldp_debug.a & LDP_DEBUG_ ## b)
#define CONF_LDP_DEBUG(a, b) (conf_ldp_debug.a & LDP_DEBUG_ ## b)
#define LDP_DEBUG(a, b) (ldp_debug.a & b)
#define CONF_LDP_DEBUG(a, b) (conf_ldp_debug.a & b)
#define debug_hello_recv(emsg, ...) \
do { \
if (LDP_DEBUG(hello, HELLO_RECV)) \
if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_RECV)) \
log_debug("discovery[recv]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_hello_send(emsg, ...) \
do { \
if (LDP_DEBUG(hello, HELLO_SEND)) \
if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_SEND)) \
log_debug("discovery[send]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_err(emsg, ...) \
do { \
if (LDP_DEBUG(errors, ERRORS)) \
if (LDP_DEBUG(errors, LDP_DEBUG_ERRORS)) \
log_debug("error: " emsg, __VA_ARGS__); \
} while (0)
#define debug_evt(emsg, ...) \
do { \
if (LDP_DEBUG(event, EVENT)) \
if (LDP_DEBUG(event, LDP_DEBUG_EVENT)) \
log_debug("event: " emsg, __VA_ARGS__); \
} while (0)
#define debug_labels(emsg, ...) \
do { \
if (LDP_DEBUG(labels, LABELS)) \
if (LDP_DEBUG(labels, LDP_DEBUG_LABELS)) \
log_debug("labels: " emsg, __VA_ARGS__); \
} while (0)
#define debug_msg_recv(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_RECV)) \
if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV)) \
log_debug("msg[in]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_msg_send(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_SEND)) \
if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND)) \
log_debug("msg[out]: " emsg, __VA_ARGS__); \
} while (0)
@ -121,25 +121,25 @@ do { \
#define debug_kalive_recv(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_RECV_ALL)) \
if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV_ALL)) \
log_debug("kalive[in]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_kalive_send(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_SEND_ALL)) \
if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND_ALL)) \
log_debug("kalive[out]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_zebra_in(emsg, ...) \
do { \
if (LDP_DEBUG(zebra, ZEBRA)) \
if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA)) \
log_debug("zebra[in]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_zebra_out(emsg, ...) \
do { \
if (LDP_DEBUG(zebra, ZEBRA)) \
if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA)) \
log_debug("zebra[out]: " emsg, __VA_ARGS__); \
} while (0)

View File

@ -190,7 +190,7 @@ struct cmd_node {
#define CMD_NOT_MY_INSTANCE 14
/* Argc max counts. */
#define CMD_ARGC_MAX 25
#define CMD_ARGC_MAX 256
/* Turn off these macros when uisng cpp with extract.pl */
#ifndef VTYSH_EXTRACT_PL

View File

@ -28,8 +28,6 @@
DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
#define MAXDEPTH 256
#ifdef TRACE_MATCHER
#define TM 1
#else
@ -84,7 +82,7 @@ static enum match_type match_mac(const char *, bool);
enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
struct list **argv, const struct cmd_element **el)
{
struct graph_node *stack[MAXDEPTH];
struct graph_node *stack[CMD_ARGC_MAX];
enum matcher_rv status;
*argv = NULL;
@ -200,7 +198,7 @@ static enum matcher_rv command_match_r(struct graph_node *start, vector vline,
/* check history/stack of tokens
* this disallows matching the same one more than once if there is a
* circle in the graph (used for keyword arguments) */
if (n == MAXDEPTH)
if (n == CMD_ARGC_MAX)
return MATCHER_NO_MATCH;
if (!token->allowrepeat)
for (size_t s = 0; s < n; s++)

View File

@ -1,5 +1,5 @@
/*
* Utilities and interfaces for managing POSIX threads
* Utilities and interfaces for managing POSIX threads within FRR.
* Copyright (C) 2017 Cumulus Networks
*
* This program is free software; you can redistribute it and/or modify
@ -19,83 +19,105 @@
#include <zebra.h>
#include <pthread.h>
#include <sched.h>
#include "frr_pthread.h"
#include "memory.h"
#include "hash.h"
DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread");
DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives");
/* id for next created pthread */
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;
/* default frr_pthread start/stop routine prototypes */
static void *fpt_run(void *arg);
static int fpt_halt(struct frr_pthread *fpt, void **res);
/* pthread_table->hash_cmp */
static int pthread_table_hash_cmp(const void *value1, const void *value2)
/* default frr_pthread attributes */
struct frr_pthread_attr frr_pthread_attr_default = {
.id = 0,
.start = fpt_run,
.stop = fpt_halt,
.name = "Anonymous",
};
/* hash table to keep track of all frr_pthreads */
static struct hash *frr_pthread_hash;
static pthread_mutex_t frr_pthread_hash_mtx = PTHREAD_MUTEX_INITIALIZER;
/* frr_pthread_hash->hash_cmp */
static int frr_pthread_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);
return (tq1->attr.id == tq2->attr.id);
}
/* pthread_table->hash_key */
static unsigned int pthread_table_hash_key(void *value)
/* frr_pthread_hash->hash_key */
static unsigned int frr_pthread_hash_key(void *value)
{
return ((struct frr_pthread *)value)->id;
return ((struct frr_pthread *)value)->attr.id;
}
/* ------------------------------------------------------------------------ */
void frr_pthread_init()
{
pthread_mutex_lock(&pthread_table_mtx);
pthread_mutex_lock(&frr_pthread_hash_mtx);
{
pthread_table = hash_create(pthread_table_hash_key,
pthread_table_hash_cmp, NULL);
frr_pthread_hash = hash_create(frr_pthread_hash_key,
frr_pthread_hash_cmp, NULL);
}
pthread_mutex_unlock(&pthread_table_mtx);
pthread_mutex_unlock(&frr_pthread_hash_mtx);
}
void frr_pthread_finish()
{
pthread_mutex_lock(&pthread_table_mtx);
pthread_mutex_lock(&frr_pthread_hash_mtx);
{
hash_clean(pthread_table,
hash_clean(frr_pthread_hash,
(void (*)(void *))frr_pthread_destroy);
hash_free(pthread_table);
hash_free(frr_pthread_hash);
}
pthread_mutex_unlock(&pthread_table_mtx);
pthread_mutex_unlock(&frr_pthread_hash_mtx);
}
struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
void *(*start_routine)(void *),
int (*stop_routine)(void **,
struct frr_pthread *))
struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr)
{
static struct frr_pthread holder = {0};
struct frr_pthread *fpt = NULL;
pthread_mutex_lock(&pthread_table_mtx);
attr = attr ? attr : &frr_pthread_attr_default;
pthread_mutex_lock(&frr_pthread_hash_mtx);
{
holder.id = id;
holder.attr.id = attr->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(name);
fpt->start_routine = start_routine;
fpt->stop_routine = stop_routine;
fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
if (!hash_lookup(frr_pthread_hash, &holder)) {
fpt = XCALLOC(MTYPE_FRR_PTHREAD,
sizeof(struct frr_pthread));
/* create new thread master */
fpt->master = thread_master_create(attr->name);
/* set attributes */
fpt->attr = *attr;
if (attr == &frr_pthread_attr_default)
fpt->attr.id = frr_pthread_get_id();
/* initialize startup synchronization primitives */
fpt->running_cond_mtx = XCALLOC(
MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM,
sizeof(pthread_cond_t));
pthread_mutex_init(fpt->running_cond_mtx, NULL);
pthread_cond_init(fpt->running_cond, NULL);
hash_get(pthread_table, fpt, hash_alloc_intern);
/* insert into global thread hash */
hash_get(frr_pthread_hash, fpt, hash_alloc_intern);
}
}
pthread_mutex_unlock(&pthread_table_mtx);
pthread_mutex_unlock(&frr_pthread_hash_mtx);
return fpt;
}
@ -103,7 +125,11 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
void frr_pthread_destroy(struct frr_pthread *fpt)
{
thread_master_free(fpt->master);
XFREE(MTYPE_FRR_PTHREAD, fpt->name);
pthread_mutex_destroy(fpt->running_cond_mtx);
pthread_cond_destroy(fpt->running_cond);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
XFREE(MTYPE_FRR_PTHREAD, fpt);
}
@ -112,73 +138,143 @@ 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);
pthread_mutex_lock(&frr_pthread_hash_mtx);
{
holder.id = id;
fpt = hash_lookup(pthread_table, &holder);
holder.attr.id = id;
fpt = hash_lookup(frr_pthread_hash, &holder);
}
pthread_mutex_unlock(&pthread_table_mtx);
pthread_mutex_unlock(&frr_pthread_hash_mtx);
return fpt;
}
int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg)
int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
{
struct frr_pthread *fpt = frr_pthread_get(id);
int ret;
if (!fpt)
return -1;
ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt);
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. */
/*
* 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)
void frr_pthread_wait_running(struct frr_pthread *fpt)
{
int ret = (*fpt->stop_routine)(result, fpt);
pthread_mutex_lock(fpt->running_cond_mtx);
{
while (!fpt->running)
pthread_cond_wait(fpt->running_cond,
fpt->running_cond_mtx);
}
pthread_mutex_unlock(fpt->running_cond_mtx);
}
void frr_pthread_notify_running(struct frr_pthread *fpt)
{
pthread_mutex_lock(fpt->running_cond_mtx);
{
fpt->running = true;
pthread_cond_signal(fpt->running_cond);
}
pthread_mutex_unlock(fpt->running_cond_mtx);
}
int frr_pthread_stop(struct frr_pthread *fpt, void **result)
{
int ret = (*fpt->attr.stop)(fpt, result);
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);
frr_pthread_stop(fpt, NULL);
}
void frr_pthread_stop_all()
{
pthread_mutex_lock(&pthread_table_mtx);
pthread_mutex_lock(&frr_pthread_hash_mtx);
{
hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
hash_iterate(frr_pthread_hash, frr_pthread_stop_all_iter, NULL);
}
pthread_mutex_unlock(&pthread_table_mtx);
pthread_mutex_unlock(&frr_pthread_hash_mtx);
}
unsigned int frr_pthread_get_id()
{
/* just a sanity check, this should never happen */
assert(next_id <= INT_MAX - 1);
return next_id++;
}
void frr_pthread_yield(void)
{
(void)sched_yield();
}
/*
* ----------------------------------------------------------------------------
* Default Event Loop
* ----------------------------------------------------------------------------
*/
/* dummy task for sleeper pipe */
static int fpt_dummy(struct thread *thread)
{
return 0;
}
/* poison pill task to end event loop */
static int fpt_finish(struct thread *thread)
{
struct frr_pthread *fpt = THREAD_ARG(thread);
atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
return 0;
}
/* stop function, called from other threads to halt this one */
static int fpt_halt(struct frr_pthread *fpt, void **res)
{
thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
pthread_join(fpt->thread, res);
fpt = NULL;
return 0;
}
/* entry pthread function & main event loop */
static void *fpt_run(void *arg)
{
struct frr_pthread *fpt = arg;
fpt->master->owner = pthread_self();
int sleeper[2];
pipe(sleeper);
thread_add_read(fpt->master, &fpt_dummy, NULL, sleeper[0], NULL);
fpt->master->handle_signals = false;
frr_pthread_notify_running(fpt);
struct thread task;
while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
if (thread_fetch(fpt->master, &task)) {
thread_call(&task);
}
}
close(sleeper[1]);
close(sleeper[0]);
return NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Utilities and interfaces for managing POSIX threads
* Utilities and interfaces for managing POSIX threads within FRR.
* Copyright (C) 2017 Cumulus Networks
*
* This program is free software; you can redistribute it and/or modify
@ -21,36 +21,73 @@
#define _FRR_PTHREAD_H
#include <pthread.h>
#include "frratomic.h"
#include "memory.h"
#include "thread.h"
DECLARE_MTYPE(FRR_PTHREAD);
DECLARE_MTYPE(PTHREAD_PRIM);
struct frr_pthread;
struct frr_pthread_attr;
struct frr_pthread_attr {
int id;
void *(*start)(void *);
int (*stop)(struct frr_pthread *, void **);
const char *name;
};
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 *);
/* caller-specified data; start & stop funcs, name, id */
struct frr_pthread_attr attr;
/* stop routine */
int (*stop_routine)(void **, struct frr_pthread *);
/*
* Notification mechanism for allowing pthreads to notify their parents
* when they are ready to do work. This mechanism has two associated
* functions:
*
* - frr_pthread_wait_running()
* This function should be called by the spawning thread after
* frr_pthread_run(). It safely waits until the spawned thread
* indicates that is ready to do work by posting to the condition
* variable.
*
* - frr_pthread_notify_running()
* This function should be called by the spawned thread when it is
* ready to do work. It will wake up any threads waiting on the
* previously described condition.
*/
pthread_cond_t *running_cond;
pthread_mutex_t *running_cond_mtx;
_Atomic bool running;
/* the (hopefully descriptive) name of this thread */
char *name;
/*
* Fake thread-specific storage. No constraints on usage. Helpful when
* creating reentrant pthread implementations. Can be used to pass
* argument to pthread entry function.
*/
void *data;
};
/* Initializes this module.
extern struct frr_pthread_attr frr_pthread_attr_default;
/*
* Initializes this module.
*
* Must be called before using any of the other functions.
*/
void frr_pthread_init(void);
/* Uninitializes this module.
/*
* Uninitializes this module.
*
* Destroys all registered frr_pthread's and internal data structures.
*
@ -59,34 +96,23 @@ void frr_pthread_init(void);
*/
void frr_pthread_finish(void);
/* Creates a new frr_pthread.
/*
* Creates a new frr_pthread with the given attributes.
*
* 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.
* The 'attr' argument should be filled out with the desired attributes,
* including ID, start and stop functions and the desired name. Alternatively,
* if attr is NULL, the default attributes will be used. The pthread will be
* set up to run a basic threadmaster loop and the name will be "Anonymous".
* Scheduling tasks onto the threadmaster in the 'master' field of the returned
* frr_pthread will cause them to run on that pthread.
*
* @param attr - the thread attributes
* @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 *));
struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr);
/* Destroys an frr_pthread.
/*
* Destroys an frr_pthread.
*
* Assumes that the associated pthread, if any, has already terminated.
*
@ -94,43 +120,75 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
*/
void frr_pthread_destroy(struct frr_pthread *fpt);
/* Gets an existing frr_pthread by its id.
/*
* 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.
/*
* 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().
* passed unmodified to pthread_create(). The frr_pthread * provided will be
* used as the argument to the pthread entry function. If it is necessary to
* pass additional data, the 'data' field in the frr_pthread may be used.
*
* 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 fpt - frr_pthread * to run
* @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);
int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr);
/* Stops an frr_pthread with a result.
/*
* Waits until the specified pthread has finished setting up and is ready to
* begin work.
*
* @param id - frr_pthread to stop
* If the pthread's code makes use of the startup synchronization mechanism,
* this function should be called before attempting to use the functionality
* exposed by the pthread. It waits until the 'running' condition is satisfied
* (see struct definition of frr_pthread).
*
* @param fpt - the frr_pthread * to wait on
*/
void frr_pthread_wait_running(struct frr_pthread *fpt);
/*
* Notifies other pthreads that the calling thread has finished setting up and
* is ready to begin work.
*
* This will allow any other pthreads waiting in 'frr_pthread_wait_running' to
* proceed.
*
* @param fpt - the frr_pthread * that has finished setting up
*/
void frr_pthread_notify_running(struct frr_pthread *fpt);
/*
* Stops a frr_pthread with a result.
*
* @param fpt - 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);
int frr_pthread_stop(struct frr_pthread *fpt, void **result);
/* Stops all frr_pthread's. */
void frr_pthread_stop_all(void);
/* Returns a unique identifier for use with frr_pthread_new().
/* Yields the current thread of execution */
void frr_pthread_yield(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

View File

@ -47,46 +47,43 @@ void frrzmq_finish(void)
}
}
/* read callback integration */
struct frrzmq_cb {
struct thread *thread;
void *zmqsock;
void *arg;
int fd;
bool cancelled;
void (*cb_msg)(void *arg, void *zmqsock);
void (*cb_part)(void *arg, void *zmqsock,
zmq_msg_t *msg, unsigned partnum);
};
static int frrzmq_read_msg(struct thread *t)
{
struct frrzmq_cb *cb = THREAD_ARG(t);
struct frrzmq_cb **cbp = THREAD_ARG(t);
struct frrzmq_cb *cb;
zmq_msg_t msg;
unsigned partno;
unsigned char read = 0;
int ret, more;
size_t moresz;
if (!cbp)
return 1;
cb = (*cbp);
if (!cb || !cb->zmqsock)
return 1;
while (1) {
zmq_pollitem_t polli = {
.socket = cb->zmqsock,
.events = ZMQ_POLLIN
};
zmq_pollitem_t polli = {.socket = cb->zmqsock,
.events = ZMQ_POLLIN};
ret = zmq_poll(&polli, 1, 0);
if (ret < 0)
goto out_err;
if (!(polli.revents & ZMQ_POLLIN))
break;
if (cb->cb_msg) {
cb->cb_msg(cb->arg, cb->zmqsock);
if (cb->read.cb_msg) {
cb->read.cb_msg(cb->read.arg, cb->zmqsock);
read = 1;
if (cb->cancelled) {
XFREE(MTYPE_ZEROMQ_CB, cb);
if (cb->read.cancelled) {
frrzmq_check_events(cbp, &cb->write,
ZMQ_POLLOUT);
cb->read.thread = NULL;
if (cb->write.cancelled && !cb->write.thread)
XFREE(MTYPE_ZEROMQ_CB, cb);
return 0;
}
continue;
@ -104,11 +101,17 @@ static int frrzmq_read_msg(struct thread *t)
zmq_msg_close(&msg);
goto out_err;
}
read = 1;
cb->cb_part(cb->arg, cb->zmqsock, &msg, partno);
if (cb->cancelled) {
cb->read.cb_part(cb->read.arg, cb->zmqsock, &msg,
partno);
if (cb->read.cancelled) {
zmq_msg_close(&msg);
XFREE(MTYPE_ZEROMQ_CB, cb);
frrzmq_check_events(cbp, &cb->write,
ZMQ_POLLOUT);
cb->read.thread = NULL;
if (cb->write.cancelled && !cb->write.thread)
XFREE(MTYPE_ZEROMQ_CB, cb);
return 0;
}
@ -116,8 +119,8 @@ static int frrzmq_read_msg(struct thread *t)
* message; don't use zmq_msg_more here */
moresz = sizeof(more);
more = 0;
ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE,
&more, &moresz);
ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE, &more,
&moresz);
if (ret < 0) {
zmq_msg_close(&msg);
goto out_err;
@ -128,64 +131,221 @@ static int frrzmq_read_msg(struct thread *t)
zmq_msg_close(&msg);
}
funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg,
cb, cb->fd, &cb->thread, t->funcname, t->schedfrom,
t->schedfrom_line);
if (read)
frrzmq_check_events(cbp, &cb->write, ZMQ_POLLOUT);
funcname_thread_add_read_write(
THREAD_READ, t->master, frrzmq_read_msg, cbp, cb->fd,
&cb->read.thread, t->funcname, t->schedfrom, t->schedfrom_line);
return 0;
out_err:
zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno);
return 0;
zlog_err("ZeroMQ read error: %s(%d)", strerror(errno), errno);
if (cb->read.cb_error)
cb->read.cb_error(cb->read.arg, cb->zmqsock);
return 1;
}
struct frrzmq_cb *funcname_frrzmq_thread_add_read(
struct thread_master *master,
void (*msgfunc)(void *arg, void *zmqsock),
void (*partfunc)(void *arg, void *zmqsock,
zmq_msg_t *msg, unsigned partnum),
void *arg, void *zmqsock, debugargdef)
int funcname_frrzmq_thread_add_read(struct thread_master *master,
void (*msgfunc)(void *arg, void *zmqsock),
void (*partfunc)(void *arg, void *zmqsock,
zmq_msg_t *msg,
unsigned partnum),
void (*errfunc)(void *arg, void *zmqsock),
void *arg, void *zmqsock,
struct frrzmq_cb **cbp, debugargdef)
{
int fd, events;
size_t len;
struct frrzmq_cb *cb;
if (!cbp)
return -1;
if (!(msgfunc || partfunc) || (msgfunc && partfunc))
return NULL;
return -1;
len = sizeof(fd);
if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
return NULL;
return -1;
len = sizeof(events);
if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
return NULL;
return -1;
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
if (!cb)
return NULL;
cb->arg = arg;
cb->zmqsock = zmqsock;
cb->cb_msg = msgfunc;
cb->cb_part = partfunc;
cb->fd = fd;
if (events & ZMQ_POLLIN)
funcname_thread_add_event(master,
frrzmq_read_msg, cb, fd, &cb->thread,
funcname, schedfrom, fromln);
else
funcname_thread_add_read_write(THREAD_READ, master,
frrzmq_read_msg, cb, fd, &cb->thread,
funcname, schedfrom, fromln);
return cb;
}
void frrzmq_thread_cancel(struct frrzmq_cb *cb)
{
if (!cb->thread) {
/* canceling from within callback */
cb->cancelled = 1;
return;
if (*cbp)
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
cb->write.cancelled = 1;
if (!cb)
return -1;
*cbp = cb;
}
cb->zmqsock = zmqsock;
cb->fd = fd;
cb->read.arg = arg;
cb->read.cb_msg = msgfunc;
cb->read.cb_part = partfunc;
cb->read.cb_error = errfunc;
cb->read.cancelled = 0;
if (events & ZMQ_POLLIN) {
if (cb->read.thread) {
thread_cancel(cb->read.thread);
cb->read.thread = NULL;
}
funcname_thread_add_event(master, frrzmq_read_msg, cbp, fd,
&cb->read.thread, funcname, schedfrom,
fromln);
} else
funcname_thread_add_read_write(
THREAD_READ, master, frrzmq_read_msg, cbp, fd,
&cb->read.thread, funcname, schedfrom, fromln);
return 0;
}
static int frrzmq_write_msg(struct thread *t)
{
struct frrzmq_cb **cbp = THREAD_ARG(t);
struct frrzmq_cb *cb;
unsigned char written = 0;
int ret;
if (!cbp)
return 1;
cb = (*cbp);
if (!cb || !cb->zmqsock)
return 1;
while (1) {
zmq_pollitem_t polli = {.socket = cb->zmqsock,
.events = ZMQ_POLLOUT};
ret = zmq_poll(&polli, 1, 0);
if (ret < 0)
goto out_err;
if (!(polli.revents & ZMQ_POLLOUT))
break;
if (cb->write.cb_msg) {
cb->write.cb_msg(cb->write.arg, cb->zmqsock);
written = 1;
if (cb->write.cancelled) {
frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
cb->write.thread = NULL;
if (cb->read.cancelled && !cb->read.thread)
XFREE(MTYPE_ZEROMQ_CB, cb);
return 0;
}
continue;
}
}
if (written)
frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
funcname_thread_add_read_write(THREAD_WRITE, t->master,
frrzmq_write_msg, cbp, cb->fd,
&cb->write.thread, t->funcname,
t->schedfrom, t->schedfrom_line);
return 0;
out_err:
zlog_err("ZeroMQ write error: %s(%d)", strerror(errno), errno);
if (cb->write.cb_error)
cb->write.cb_error(cb->write.arg, cb->zmqsock);
return 1;
}
int funcname_frrzmq_thread_add_write(struct thread_master *master,
void (*msgfunc)(void *arg, void *zmqsock),
void (*errfunc)(void *arg, void *zmqsock),
void *arg, void *zmqsock,
struct frrzmq_cb **cbp, debugargdef)
{
int fd, events;
size_t len;
struct frrzmq_cb *cb;
if (!cbp)
return -1;
if (!msgfunc)
return -1;
len = sizeof(fd);
if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
return -1;
len = sizeof(events);
if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
return -1;
if (*cbp)
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
cb->read.cancelled = 1;
if (!cb)
return -1;
*cbp = cb;
}
cb->zmqsock = zmqsock;
cb->fd = fd;
cb->write.arg = arg;
cb->write.cb_msg = msgfunc;
cb->write.cb_part = NULL;
cb->write.cb_error = errfunc;
cb->write.cancelled = 0;
if (events & ZMQ_POLLOUT) {
if (cb->write.thread) {
thread_cancel(cb->write.thread);
cb->write.thread = NULL;
}
funcname_thread_add_event(master, frrzmq_write_msg, cbp, fd,
&cb->write.thread, funcname,
schedfrom, fromln);
} else
funcname_thread_add_read_write(
THREAD_WRITE, master, frrzmq_write_msg, cbp, fd,
&cb->write.thread, funcname, schedfrom, fromln);
return 0;
}
void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core)
{
if (!cb || !*cb)
return;
core->cancelled = 1;
if (core->thread) {
thread_cancel(core->thread);
core->thread = NULL;
}
if ((*cb)->read.cancelled && !(*cb)->read.thread
&& (*cb)->write.cancelled && (*cb)->write.thread)
XFREE(MTYPE_ZEROMQ_CB, *cb);
}
void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core,
int event)
{
struct frrzmq_cb *cb;
int events;
size_t len;
if (!cbp)
return;
cb = (*cbp);
if (!cb || !cb->zmqsock)
return;
if (zmq_getsockopt(cb->zmqsock, ZMQ_EVENTS, &events, &len))
return;
if (events & event && core->thread && !core->cancelled) {
struct thread_master *tm = core->thread->master;
thread_cancel(core->thread);
core->thread = NULL;
thread_add_event(tm, (event == ZMQ_POLLIN ? frrzmq_read_msg
: frrzmq_write_msg),
cbp, cb->fd, &core->thread);
}
thread_cancel(cb->thread);
XFREE(MTYPE_ZEROMQ_CB, cb);
}

View File

@ -33,6 +33,26 @@
* foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS)
*/
/* callback integration */
struct cb_core {
struct thread *thread;
void *arg;
bool cancelled;
void (*cb_msg)(void *arg, void *zmqsock);
void (*cb_part)(void *arg, void *zmqsock, zmq_msg_t *msg,
unsigned partnum);
void (*cb_error)(void *arg, void *zmqsock);
};
struct frrzmq_cb {
void *zmqsock;
int fd;
struct cb_core read;
struct cb_core write;
};
/* libzmq's context
*
* this is mostly here as a convenience, it has IPv6 enabled but nothing
@ -40,21 +60,27 @@
*/
extern void *frrzmq_context;
extern void frrzmq_init (void);
extern void frrzmq_finish (void);
extern void frrzmq_init(void);
extern void frrzmq_finish(void);
#define debugargdef const char *funcname, const char *schedfrom, int fromln
/* core event registration, one of these 2 macros should be used */
#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \
m,f,NULL,a,z,#f,__FILE__,__LINE__)
#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \
m,NULL,f,a,z,#f,__FILE__,__LINE__)
#define frrzmq_thread_add_read_msg(m, f, e, a, z, d) \
funcname_frrzmq_thread_add_read(m, f, NULL, e, a, z, d, #f, __FILE__, \
__LINE__)
#define frrzmq_thread_add_read_part(m, f, e, a, z, d) \
funcname_frrzmq_thread_add_read(m, NULL, f, e, a, z, d, #f, __FILE__, \
__LINE__)
#define frrzmq_thread_add_write_msg(m, f, e, a, z, d) \
funcname_frrzmq_thread_add_write(m, f, e, a, z, d, #f, __FILE__, \
__LINE__)
struct cb_core;
struct frrzmq_cb;
/* Set up a POLLIN notification to be called from the libfrr main loop.
* This has the following properties:
/* Set up a POLLIN or POLLOUT notification to be called from the libfrr main
* loop. This has the following properties:
*
* - since ZeroMQ works with edge triggered notifications, it will loop and
* dispatch as many events as ZeroMQ has pending at the time libfrr calls
@ -67,22 +93,35 @@ struct frrzmq_cb;
* - if partfunc is specified, the message is read and partfunc is called
* for each ZeroMQ multi-part subpart. Note that you can't send replies
* before all parts have been read because that violates the ZeroMQ FSM.
* - write version doesn't allow for partial callback, you must handle the
* whole message (all parts) in msgfunc callback
* - you can safely cancel the callback from within itself
* - installing a callback will check for pending events (ZMQ_EVENTS) and
* may schedule the event to run as soon as libfrr is back in its main
* loop.
*
* TODO #1: add ZMQ_POLLERR / error callback
* TODO #2: add frrzmq_check_events() function to check for edge triggered
* things that may have happened after a zmq_send() call or so
*/
extern struct frrzmq_cb *funcname_frrzmq_thread_add_read(
struct thread_master *master,
void (*msgfunc)(void *arg, void *zmqsock),
void (*partfunc)(void *arg, void *zmqsock,
zmq_msg_t *msg, unsigned partnum),
void *arg, void *zmqsock, debugargdef);
extern int funcname_frrzmq_thread_add_read(
struct thread_master *master, void (*msgfunc)(void *arg, void *zmqsock),
void (*partfunc)(void *arg, void *zmqsock, zmq_msg_t *msg,
unsigned partnum),
void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock,
struct frrzmq_cb **cb, debugargdef);
extern int funcname_frrzmq_thread_add_write(
struct thread_master *master, void (*msgfunc)(void *arg, void *zmqsock),
void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock,
struct frrzmq_cb **cb, debugargdef);
extern void frrzmq_thread_cancel(struct frrzmq_cb *cb);
extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core);
/*
* http://api.zeromq.org/4-2:zmq-getsockopt#toc10
*
* As the descriptor is edge triggered, applications must update the state of
* ZMQ_EVENTS after each invocation of zmq_send or zmq_recv.To be more explicit:
* after calling zmq_send the socket may become readable (and vice versa)
* without triggering a read event on the file descriptor.
*/
extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core,
int event);
#endif /* _FRRZMQ_H */

View File

@ -33,8 +33,6 @@
DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
#define MAXDEPTH 64
/** headers **/
void grammar_sandbox_init(void);
void pretty_print_graph(struct vty *vty, struct graph_node *, int, int,
@ -262,7 +260,7 @@ DEFUN (grammar_test_show,
{
check_nodegraph();
struct graph_node *stack[MAXDEPTH];
struct graph_node *stack[CMD_ARGC_MAX];
pretty_print_graph(vty, vector_slot(nodegraph->nodes, 0), 0, argc >= 3,
stack, 0);
return CMD_SUCCESS;
@ -277,8 +275,8 @@ DEFUN (grammar_test_dot,
{
check_nodegraph();
struct graph_node *stack[MAXDEPTH];
struct graph_node *visited[MAXDEPTH * MAXDEPTH];
struct graph_node *stack[CMD_ARGC_MAX];
struct graph_node *visited[CMD_ARGC_MAX * CMD_ARGC_MAX];
size_t vpos = 0;
FILE *ofd = fopen(argv[2]->arg, "w");
@ -334,7 +332,7 @@ static void cmd_graph_permute(struct list *out, struct graph_node **stack,
return;
}
if (++stackpos == MAXDEPTH)
if (++stackpos == CMD_ARGC_MAX)
return;
for (i = 0; i < vector_active(gn->to); i++) {
@ -354,7 +352,7 @@ static void cmd_graph_permute(struct list *out, struct graph_node **stack,
static struct list *cmd_graph_permutations(struct graph *graph)
{
char accumulate[2048] = "";
struct graph_node *stack[MAXDEPTH];
struct graph_node *stack[CMD_ARGC_MAX];
struct list *rv = list_new();
rv->cmp = cmd_permute_cmp;
@ -532,7 +530,7 @@ void pretty_print_graph(struct vty *vty, struct graph_node *start, int level,
vty_out(vty, " ?'%s'", tok->desc);
vty_out(vty, " ");
if (stackpos == MAXDEPTH) {
if (stackpos == CMD_ARGC_MAX) {
vty_out(vty, " -aborting! (depth limit)\n");
return;
}
@ -586,7 +584,7 @@ static void pretty_print_dot(FILE *ofd, unsigned opts, struct graph_node *start,
if (visited[i] == start)
return;
visited[(*visitpos)++] = start;
if ((*visitpos) == MAXDEPTH * MAXDEPTH)
if ((*visitpos) == CMD_ARGC_MAX * CMD_ARGC_MAX)
return;
snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
@ -626,7 +624,7 @@ static void pretty_print_dot(FILE *ofd, unsigned opts, struct graph_node *start,
}
fprintf(ofd, ">, style = filled, fillcolor = \"%s\" ];\n", color);
if (stackpos == MAXDEPTH)
if (stackpos == CMD_ARGC_MAX)
return;
stack[stackpos++] = start;

View File

@ -210,6 +210,9 @@ void if_delete(struct interface *ifp)
if_link_params_free(ifp);
if (ifp->desc)
XFREE(MTYPE_TMP, ifp->desc);
XFREE(MTYPE_IF, ifp);
}
@ -219,6 +222,18 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
struct vrf *vrf;
struct interface if_tmp;
if (vrf_id == VRF_UNKNOWN) {
struct interface *ifp;
RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
if (ifp)
return ifp;
}
return NULL;
}
vrf = vrf_lookup_by_id(vrf_id);
if (!vrf)
return NULL;
@ -663,8 +678,9 @@ DEFUN_NOSH (no_interface,
"Interface's name\n"
VRF_CMD_HELP_STR)
{
int idx_vrf = 4;
const char *ifname = argv[2]->arg;
const char *vrfname = (argc > 3) ? argv[3]->arg : NULL;
const char *vrfname = (argc > 3) ? argv[idx_vrf]->arg : NULL;
// deleting interface
struct interface *ifp;

View File

@ -452,6 +452,13 @@ struct nbr_connected {
/* Prototypes. */
extern int if_cmp_name_func(char *, char *);
/*
* Passing in VRF_UNKNOWN is a valid thing to do, unless we
* are creating a new interface.
*
* This is useful for vrf route-leaking. So more than anything
* else think before you use VRF_UNKNOWN
*/
extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
extern struct interface *if_create(const char *name, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);

View File

@ -945,6 +945,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_VNI_ADD),
DESC_ENTRY(ZEBRA_VNI_DEL),
DESC_ENTRY(ZEBRA_L3VNI_ADD),
DESC_ENTRY(ZEBRA_L3VNI_DEL),
DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD),
DESC_ENTRY(ZEBRA_REMOTE_VTEP_DEL),
DESC_ENTRY(ZEBRA_MACIP_ADD),

View File

@ -1,7 +1,3 @@
/* $USAGI: md5.c,v 1.2 2000/11/02 11:59:24 yoshfuji Exp $ */
/* $KAME: md5.c,v 1.2 2000/05/27 07:07:48 jinmei Exp $ */
/* $Id: md5.c,v 1.6 2006/01/17 23:39:04 vincent Exp $ */
/*
* Copyright (C) 2004 6WIND
* <Vincent.Jardin@6WIND.com>

View File

@ -1,7 +1,3 @@
/* $USAGI: md5.h,v 1.2 2000/11/02 11:59:25 yoshfuji Exp $ */
/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */
/* $Id: md5.h,v 1.3 2006/01/17 17:40:45 paul Exp $ */
/*
* Copyright (C) 2004 6WIND
* <Vincent.Jardin@6WIND.com>

View File

@ -81,6 +81,12 @@ typedef unsigned int mpls_lse_t;
/* MPLS label value as a 32-bit (mostly we only care about the label value). */
typedef unsigned int mpls_label_t;
struct mpls_label_stack {
uint8_t num_labels;
uint8_t reserved[3];
mpls_label_t label[0]; /* 1 or more labels */
};
/* The MPLS explicit-null label is 0 which means when you memset a mpls_label_t
* to zero you have set that variable to explicit-null which was probably not
* your intent. The work-around is to use one bit to indicate if the

View File

@ -124,7 +124,7 @@ const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
*/
int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
{
struct nexthop_label *nhl1, *nhl2;
struct mpls_label_stack *nhl1, *nhl2;
nhl1 = nh1->nh_label;
nhl2 = nh2->nh_label;
@ -210,12 +210,12 @@ void nexthops_free(struct nexthop *nexthop)
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
u_int8_t num_labels, mpls_label_t *label)
{
struct nexthop_label *nh_label;
struct mpls_label_stack *nh_label;
int i;
nexthop->nh_label_type = type;
nh_label = XCALLOC(MTYPE_NH_LABEL,
sizeof(struct nexthop_label)
sizeof(struct mpls_label_stack)
+ num_labels * sizeof(mpls_label_t));
nh_label->num_labels = num_labels;
for (i = 0; i < num_labels; i++)

View File

@ -55,13 +55,6 @@ enum blackhole_type {
((type) == NEXTHOP_TYPE_IFINDEX || (type) == NEXTHOP_TYPE_BLACKHOLE) \
? (type) : ((type) | 1)
/* Nexthop label structure. */
struct nexthop_label {
u_int8_t num_labels;
u_int8_t reserved[3];
mpls_label_t label[0]; /* 1 or more labels. */
};
/* Nexthop structure. */
struct nexthop {
struct nexthop *next;
@ -80,6 +73,7 @@ struct nexthop {
#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */
#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */
#define NEXTHOP_FLAG_DUPLICATE (1 << 6) /* nexthop duplicates another active one */
#define NEXTHOP_FLAG_EVPN_RVTEP (1 << 7) /* EVPN remote vtep nexthop */
#define NEXTHOP_IS_ACTIVE(flags) \
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
&& !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
@ -106,7 +100,7 @@ struct nexthop {
enum lsp_types_t nh_label_type;
/* Label(s) associated with this nexthop. */
struct nexthop_label *nh_label;
struct mpls_label_stack *nh_label;
};
/* The following for loop allows to iterate over the nexthop

View File

@ -25,10 +25,11 @@
#include "openbsd-tree.h"
#include "linklist.h"
typedef u_int16_t ns_id_t;
typedef u_int32_t ns_id_t;
/* The default NS ID */
/* the default NS ID */
#define NS_DEFAULT 0
#define NS_UNKNOWN UINT32_MAX
/* Default netns directory (Linux) */
#define NS_RUN_DIR "/var/run/netns"

View File

@ -301,7 +301,7 @@ static const struct in6_addr maskbytes6[] = {
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
static int is_zero_mac(const struct ethaddr *mac)
int is_zero_mac(struct ethaddr *mac)
{
int i = 0;
@ -1043,10 +1043,11 @@ static const char *prefixevpn2str(const struct prefix *p, char *str, int size)
family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)
? AF_INET
: AF_INET6;
snprintf(str, size, "[%d]:[%u][%s]/%d",
snprintf(str, size, "[%d]:[%u][%s/%d]/%d",
p->u.prefix_evpn.route_type, p->u.prefix_evpn.eth_tag,
inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, buf,
PREFIX2STR_BUFFER),
p->u.prefix_evpn.ip_prefix_length,
p->prefixlen);
} else {
sprintf(str, "Unsupported EVPN route type %d",

View File

@ -348,6 +348,7 @@ extern void masklen2ip6(const int, struct in6_addr *);
extern const char *inet6_ntoa(struct in6_addr);
extern int is_zero_mac(struct ethaddr *mac);
extern int prefix_str2mac(const char *str, struct ethaddr *mac);
extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
@ -398,4 +399,13 @@ static inline int is_default_prefix(const struct prefix *p)
return 0;
}
static inline int is_host_route(struct prefix *p)
{
if (p->family == AF_INET)
return (p->prefixlen == IPV4_MAX_BITLEN);
else if (p->family == AF_INET6)
return (p->prefixlen == IPV6_MAX_BITLEN);
return 0;
}
#endif /* _ZEBRA_PREFIX_H */

View File

@ -223,6 +223,25 @@ int ptm_lib_init_msg(ptm_lib_handle_t *hdl, int cmd_id, int type, void *in_ctxt,
return 0;
}
int ptm_lib_cleanup_msg(ptm_lib_handle_t *hdl, void *ctxt)
{
ptm_lib_msg_ctxt_t *p_ctxt = ctxt;
csv_t *csv;
if (!p_ctxt) {
ERRLOG("%s: no context \n", __FUNCTION__);
return -1;
}
csv = p_ctxt->csv;
csv_clean(csv);
csv_free(csv);
free(p_ctxt);
return 0;
}
int ptm_lib_complete_msg(ptm_lib_handle_t *hdl, void *ctxt, char *buf, int *len)
{
ptm_lib_msg_ctxt_t *p_ctxt = ctxt;

View File

@ -63,5 +63,6 @@ int ptm_lib_find_key_in_msg(void *, const char *, char *);
int ptm_lib_init_msg(ptm_lib_handle_t *, int, int, void *, void **);
int ptm_lib_append_msg(ptm_lib_handle_t *, void *, const char *, const char *);
int ptm_lib_complete_msg(ptm_lib_handle_t *, void *, char *, int *);
int ptm_lib_cleanup_msg(ptm_lib_handle_t *, void *);
#endif

133
lib/ringbuf.c Normal file
View File

@ -0,0 +1,133 @@
/*
* Circular buffer implementation.
* Copyright (C) 2017 Cumulus Networks
* Quentin Young
*
* 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 "ringbuf.h"
#include "memory.h"
DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer")
struct ringbuf *ringbuf_new(size_t size)
{
struct ringbuf *buf = XCALLOC(MTYPE_RINGBUFFER, sizeof(struct ringbuf));
buf->data = XCALLOC(MTYPE_RINGBUFFER, size);
buf->size = size;
buf->empty = true;
return buf;
}
void ringbuf_del(struct ringbuf *buf)
{
XFREE(MTYPE_RINGBUFFER, buf->data);
XFREE(MTYPE_RINGBUFFER, buf);
}
size_t ringbuf_remain(struct ringbuf *buf)
{
ssize_t diff = buf->end - buf->start;
diff += ((diff == 0) && !buf->empty) ? buf->size : 0;
diff += (diff < 0) ? buf->size : 0;
return (size_t)diff;
}
size_t ringbuf_space(struct ringbuf *buf)
{
return buf->size - ringbuf_remain(buf);
}
size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size)
{
const uint8_t *dp = data;
size_t space = ringbuf_space(buf);
size_t copysize = MIN(size, space);
size_t tocopy = copysize;
if (tocopy >= buf->size - buf->end) {
size_t ts = buf->size - buf->end;
memcpy(buf->data + buf->end, dp, ts);
buf->end = 0;
tocopy -= ts;
dp += ts;
}
memcpy(buf->data + buf->end, dp, tocopy);
buf->end += tocopy;
buf->empty = (buf->start == buf->end) && (buf->empty && !copysize);
return copysize;
}
size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size)
{
uint8_t *dp = data;
size_t remain = ringbuf_remain(buf);
size_t copysize = MIN(remain, size);
size_t tocopy = copysize;
if (tocopy >= buf->size - buf->start) {
size_t ts = buf->size - buf->start;
memcpy(dp, buf->data + buf->start, ts);
buf->start = 0;
tocopy -= ts;
dp += ts;
}
memcpy(dp, buf->data + buf->start, tocopy);
buf->start = buf->start + tocopy;
buf->empty = (buf->start == buf->end) && (buf->empty || copysize);
return copysize;
}
size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data, size_t size)
{
uint8_t *dp = data;
size_t remain = ringbuf_remain(buf);
if (offset >= remain)
return 0;
size_t copysize = MAX(MIN(remain - offset, size), (size_t) 0);
size_t tocopy = copysize;
size_t cstart = (buf->start + offset) % buf->size;
if (tocopy >= buf->size - cstart) {
size_t ts = buf->size - cstart;
memcpy(dp, buf->data + cstart, ts);
cstart = 0;
tocopy -= ts;
dp += ts;
}
memcpy(dp, buf->data + cstart, tocopy);
return copysize;
}
size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size)
{
size_t tocopy = MIN(ringbuf_space(to), size);
uint8_t *cbuf = XCALLOC(MTYPE_TMP, tocopy);
tocopy = ringbuf_peek(from, 0, cbuf, tocopy);
size_t put = ringbuf_put(to, cbuf, tocopy);
XFREE(MTYPE_TMP, cbuf);
return put;
}
void ringbuf_reset(struct ringbuf *buf)
{
buf->start = buf->end = 0;
buf->empty = true;
}
void ringbuf_wipe(struct ringbuf *buf)
{
memset(buf->data, 0x00, buf->size);
ringbuf_reset(buf);
}

125
lib/ringbuf.h Normal file
View File

@ -0,0 +1,125 @@
/*
* Circular buffer implementation.
* Copyright (C) 2017 Cumulus Networks
* Quentin Young
*
* 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_RINGBUF_H_
#define _FRR_RINGBUF_H_
#include <zebra.h>
#include <stdint.h>
#include "memory.h"
struct ringbuf {
size_t size;
ssize_t start;
ssize_t end;
bool empty;
uint8_t *data;
};
/*
* Creates a new ring buffer.
*
* @param size buffer size, in bytes
* @return the newly created buffer
*/
struct ringbuf *ringbuf_new(size_t size);
/*
* Deletes a ring buffer and frees all associated resources.
*
* @param buf the ring buffer to destroy
*/
void ringbuf_del(struct ringbuf *buf);
/*
* Get amount of data left to read from the buffer.
*
* @return number of readable bytes
*/
size_t ringbuf_remain(struct ringbuf *buf);
/*
* Get amount of space left to write to the buffer
*
* @return number of writeable bytes
*/
size_t ringbuf_space(struct ringbuf *buf);
/*
* Put data into the ring buffer.
*
* @param data the data to put in the buffer
* @param size how much of data to put in
* @return number of bytes written; will be less than size if there was not
* enough space
*/
size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size);
/*
* Get data from the ring buffer.
*
* @param data where to put the data
* @param size how much of data to get
* @return number of bytes read into data; will be less than size if there was
* not enough data to read
*/
size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size);
/*
* Peek data from the ring buffer.
*
* @param offset where to get the data from, in bytes offset from the
* start of the data
* @param data where to put the data
* @param size how much data to get
* @return number of bytes read into data; will be less than size
* if there was not enough data to read; will be -1 if the
* offset exceeds the amount of data left in the ring
* buffer
*/
size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data,
size_t size);
/*
* Copy data from one ringbuf to another.
*
* @param to destination ringbuf
* @param from source ringbuf
* @param size how much data to copy
* @return amount of data copied
*/
size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size);
/*
* Reset buffer. Does not wipe.
*
* @param buf
*/
void ringbuf_reset(struct ringbuf *buf);
/*
* Reset buffer. Wipes.
*
* @param buf
*/
void ringbuf_wipe(struct ringbuf *buf);
#endif /* _FRR_RINGBUF_H_ */

View File

@ -51,6 +51,7 @@ lib_libfrr_la_SOURCES = \
lib/privs.c \
lib/ptm_lib.c \
lib/qobj.c \
lib/ringbuf.c \
lib/routemap.c \
lib/sbuf.c \
lib/sha256.c \
@ -130,6 +131,7 @@ pkginclude_HEADERS += \
lib/pw.h \
lib/qobj.h \
lib/queue.h \
lib/ringbuf.h \
lib/routemap.h \
lib/sbuf.h \
lib/sha256.h \

View File

@ -919,6 +919,8 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
*/
static void thread_cancel_rw(struct thread_master *master, int fd, short state)
{
bool found = false;
/* Cancel POLLHUP too just in case some bozo set it */
state |= POLLHUP;
@ -926,8 +928,18 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
nfds_t i;
for (i = 0; i < master->handler.pfdcount; i++)
if (master->handler.pfds[i].fd == fd)
if (master->handler.pfds[i].fd == fd) {
found = true;
break;
}
if (!found) {
zlog_debug(
"[!] Received cancellation request for nonexistent rw job");
zlog_debug("[!] threadmaster: %s | fd: %d",
master->name ? master->name : "", fd);
return;
}
/* NOT out event. */
master->handler.pfds[i].events &= ~(state);

View File

@ -94,7 +94,7 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
int new = 0;
if (debug_vrf)
zlog_debug("VRF_GET: %s(%d)", name, vrf_id);
zlog_debug("VRF_GET: %s(%u)", name, vrf_id);
/* Nothing to see, move along here */
if (!name && vrf_id == VRF_UNKNOWN)
@ -225,6 +225,17 @@ static void vrf_disable(struct vrf *vrf)
(*vrf_master.vrf_disable_hook)(vrf);
}
const char *vrf_id_to_name(vrf_id_t vrf_id)
{
struct vrf *vrf;
vrf = vrf_lookup_by_id(vrf_id);
if (vrf)
return vrf->name;
return "n/a";
}
vrf_id_t vrf_name_to_id(const char *name)
{
struct vrf *vrf;
@ -256,8 +267,8 @@ void *vrf_info_lookup(vrf_id_t vrf_id)
* VRF bit-map
*/
#define VRF_BITMAP_NUM_OF_GROUPS 8
#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS)
#define VRF_BITMAP_NUM_OF_GROUPS 1024
#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS)
#define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \
(VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
@ -344,7 +355,7 @@ static void vrf_autocomplete(vector comps, struct cmd_token *token)
struct vrf *vrf = NULL;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (vrf->vrf_id != 0)
if (vrf->vrf_id != VRF_DEFAULT)
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name));
}
}

View File

@ -32,8 +32,7 @@
/* The default VRF ID */
#define VRF_DEFAULT 0
#define VRF_UNKNOWN UINT16_MAX
#define VRF_ALL UINT16_MAX - 1
#define VRF_UNKNOWN UINT32_MAX
/* Pending: May need to refine this. */
#ifndef IFLA_VRF_MAX
@ -103,6 +102,7 @@ extern struct vrf_name_head vrfs_by_name;
extern struct vrf *vrf_lookup_by_id(vrf_id_t);
extern struct vrf *vrf_lookup_by_name(const char *);
extern struct vrf *vrf_get(vrf_id_t, const char *);
extern const char *vrf_id_to_name(vrf_id_t vrf_id);
extern vrf_id_t vrf_name_to_id(const char *);
#define VRF_GET_ID(V, NAME) \

View File

@ -1,6 +1,4 @@
/*
* $Id: zassert.h,v 1.2 2004/12/03 18:01:04 ajs Exp $
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it

View File

@ -291,7 +291,7 @@ void zclient_create_header(struct stream *s, uint16_t command, vrf_id_t vrf_id)
stream_putw(s, ZEBRA_HEADER_SIZE);
stream_putc(s, ZEBRA_HEADER_MARKER);
stream_putc(s, ZSERV_VERSION);
stream_putw(s, vrf_id);
stream_putl(s, vrf_id);
stream_putw(s, command);
}
@ -306,7 +306,7 @@ int zclient_read_header(struct stream *s, int sock, u_int16_t *size,
*size -= ZEBRA_HEADER_SIZE;
STREAM_GETC(s, *marker);
STREAM_GETC(s, *version);
STREAM_GETW(s, *vrf_id);
STREAM_GETL(s, *vrf_id);
STREAM_GETW(s, *cmd);
if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) {
@ -389,25 +389,28 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
vrf_id);
/* Flush all redistribute request. */
if (vrf_id == VRF_DEFAULT)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (zclient->mi_redist[afi][i].enabled) {
struct listnode *node;
u_short *id;
if (vrf_id == VRF_DEFAULT) {
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (!zclient->mi_redist[afi][i].enabled)
continue;
for (ALL_LIST_ELEMENTS_RO(
zclient->mi_redist[afi][i]
.instances,
node, id))
if (!(i == zclient->redist_default
&& *id == zclient->instance))
zebra_redistribute_send(
ZEBRA_REDISTRIBUTE_ADD,
zclient, afi, i,
*id,
VRF_DEFAULT);
}
struct listnode *node;
u_short *id;
for (ALL_LIST_ELEMENTS_RO(
zclient->mi_redist[afi][i]
.instances, node, id))
if (!(i == zclient->redist_default
&& *id == zclient->instance))
zebra_redistribute_send(
ZEBRA_REDISTRIBUTE_ADD,
zclient, afi, i,
*id,
VRF_DEFAULT);
}
}
}
/* Flush all redistribute request. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
@ -447,29 +450,32 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
/* Set unwanted redistribute route. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
vrf_bitmap_set(zclient->redist[afi][zclient->redist_default],
vrf_id);
vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default],
vrf_id);
/* Flush all redistribute request. */
if (vrf_id == VRF_DEFAULT)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (zclient->mi_redist[afi][i].enabled) {
struct listnode *node;
u_short *id;
if (vrf_id == VRF_DEFAULT) {
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (!zclient->mi_redist[afi][i].enabled)
continue;
for (ALL_LIST_ELEMENTS_RO(
zclient->mi_redist[afi][i]
.instances,
node, id))
if (!(i == zclient->redist_default
&& *id == zclient->instance))
zebra_redistribute_send(
ZEBRA_REDISTRIBUTE_DELETE,
zclient, afi, i,
*id,
VRF_DEFAULT);
}
struct listnode *node;
u_short *id;
for (ALL_LIST_ELEMENTS_RO(
zclient->mi_redist[afi][i]
.instances, node, id))
if (!(i == zclient->redist_default
&& *id == zclient->instance))
zebra_redistribute_send(
ZEBRA_REDISTRIBUTE_DELETE,
zclient, afi, i,
*id,
VRF_DEFAULT);
}
}
}
/* Flush all redistribute request. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
@ -608,6 +614,33 @@ static int zclient_connect(struct thread *t)
return zclient_start(zclient);
}
int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p,
bool exact_match, vrf_id_t vrf_id)
{
struct stream *s;
s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, command, vrf_id);
stream_putc(s, (exact_match) ? 1 : 0);
stream_putw(s, PREFIX_FAMILY(p));
stream_putc(s, p->prefixlen);
switch (PREFIX_FAMILY(p)) {
case AF_INET:
stream_put_in_addr(s, &p->u.prefix4);
break;
case AF_INET6:
stream_put(s, &(p->u.prefix6), 16);
break;
default:
break;
}
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
}
/*
* "xdr_encode"-like interface that allows daemon (client) to send
* a message to zebra server for a route that needs to be
@ -912,6 +945,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
stream_putl(s, api->flags);
stream_putc(s, api->message);
stream_putc(s, api->safi);
if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
stream_put(s, &(api->rmac), sizeof(struct ethaddr));
/* Put prefix information. */
stream_putc(s, api->prefix.family);
@ -940,6 +975,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
}
stream_putw(s, api->nexthop_num);
if (api->nexthop_num)
stream_putw(s, api->nh_vrf_id);
for (i = 0; i < api->nexthop_num; i++) {
api_nh = &api->nexthops[i];
@ -1032,6 +1069,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
STREAM_GETL(s, api->flags);
STREAM_GETC(s, api->message);
STREAM_GETC(s, api->safi);
if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
stream_get(&(api->rmac), s, sizeof(struct ethaddr));
/* Prefix. */
STREAM_GETC(s, api->prefix.family);
@ -1087,6 +1126,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
return -1;
}
if (api->nexthop_num)
STREAM_GETW(s, api->nh_vrf_id);
for (i = 0; i < api->nexthop_num; i++) {
api_nh = &api->nexthops[i];
@ -1673,7 +1715,7 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s,
{
unsigned int ifindex;
struct interface *ifp;
vrf_id_t new_id = VRF_DEFAULT;
vrf_id_t new_id;
/* Get interface index. */
ifindex = stream_getl(s);
@ -2039,7 +2081,7 @@ static int zclient_read(struct thread *thread)
length = stream_getw(zclient->ibuf);
marker = stream_getc(zclient->ibuf);
version = stream_getc(zclient->ibuf);
vrf_id = stream_getw(zclient->ibuf);
vrf_id = stream_getl(zclient->ibuf);
command = stream_getw(zclient->ibuf);
if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
@ -2205,6 +2247,16 @@ static int zclient_read(struct thread *thread)
(*zclient->local_vni_del)(command, zclient, length,
vrf_id);
break;
case ZEBRA_L3VNI_ADD:
if (zclient->local_l3vni_add)
(*zclient->local_l3vni_add)(command, zclient, length,
vrf_id);
break;
case ZEBRA_L3VNI_DEL:
if (zclient->local_l3vni_del)
(*zclient->local_l3vni_del)(command, zclient, length,
vrf_id);
break;
case ZEBRA_MACIP_ADD:
if (zclient->local_macip_add)
(*zclient->local_macip_add)(command, zclient, length,
@ -2332,9 +2384,9 @@ void zclient_interface_set_master(struct zclient *client,
zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id);
stream_putw(s, master->vrf_id);
stream_putl(s, master->vrf_id);
stream_putl(s, master->ifindex);
stream_putw(s, slave->vrf_id);
stream_putl(s, slave->vrf_id);
stream_putl(s, slave->ifindex);
stream_putw_at(s, 0, stream_get_endp(s));

View File

@ -40,7 +40,7 @@
#define ZEBRA_MAX_PACKET_SIZ 4096
/* Zebra header size. */
#define ZEBRA_HEADER_SIZE 8
#define ZEBRA_HEADER_SIZE 10
/* special socket path name to use TCP
* @ is used as first character because that's abstract socket names on Linux
@ -112,6 +112,8 @@ typedef enum {
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL,
ZEBRA_L3VNI_ADD,
ZEBRA_L3VNI_DEL,
ZEBRA_REMOTE_VTEP_ADD,
ZEBRA_REMOTE_VTEP_DEL,
ZEBRA_MACIP_ADD,
@ -200,6 +202,8 @@ struct zclient {
int (*fec_update)(int, struct zclient *, uint16_t);
int (*local_vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_l3vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t);
int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t);
@ -223,7 +227,7 @@ struct zserv_header {
* always set to 255 in new zserv.
*/
uint8_t version;
#define ZSERV_VERSION 4
#define ZSERV_VERSION 5
vrf_id_t vrf_id;
uint16_t command;
};
@ -277,6 +281,9 @@ struct zapi_route {
u_int32_t mtu;
vrf_id_t vrf_id;
vrf_id_t nh_vrf_id;
struct ethaddr rmac;
};
/* Zebra IPv4 route message API. */
@ -414,6 +421,11 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
vrf_id_t *new_vrf_id);
extern void zebra_interface_if_set_value(struct stream *, struct interface *);
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
#if CONFDATE > 20180823
CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
#endif
extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *,
struct zapi_ipv4 *) __attribute__((deprecated));
@ -472,6 +484,9 @@ extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *,
struct zapi_ipv6 *)
__attribute__((deprecated));
extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *);
extern int zclient_send_rnh(struct zclient *zclient, int command,
struct prefix *p, bool exact_match,
vrf_id_t vrf_id);
extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *);
extern int zapi_route_decode(struct stream *, struct zapi_route *);
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,

View File

@ -409,6 +409,7 @@ extern const char *zserv_command_string(unsigned int command);
#define ZEBRA_FLAG_STATIC 0x40
#define ZEBRA_FLAG_SCOPE_LINK 0x100
#define ZEBRA_FLAG_FIB_OVERRIDE 0x200
#define ZEBRA_FLAG_EVPN_ROUTE 0x400
/* ZEBRA_FLAG_BLACKHOLE was 0x04 */
/* ZEBRA_FLAG_REJECT was 0x80 */
@ -485,7 +486,7 @@ typedef u_int16_t zebra_size_t;
typedef u_int16_t zebra_command_t;
/* VRF ID type. */
typedef u_int16_t vrf_id_t;
typedef uint32_t vrf_id_t;
typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX

Some files were not shown because too many files have changed in this diff Show More