mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-26 05:09:12 +00:00
Merge branch 'master' into docs-user
Manually merged these doc commits:3bb7cd7f56ff21655441
This commit is contained in:
commit
d38549c99d
@ -57,3 +57,5 @@ ForEachMacros:
|
||||
- SUBGRP_FOREACH_ADJ_SAFE
|
||||
- AF_FOREACH
|
||||
- FOREACH_AFI_SAFI
|
||||
# ospfd
|
||||
- LSDB_LOOP
|
||||
|
||||
10
COMMUNITY.md
10
COMMUNITY.md
@ -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
12
README
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
1570
bgpd/bgp_evpn.c
1570
bgpd/bgp_evpn.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
||||
@ -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
@ -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);
|
||||
|
||||
|
||||
221
bgpd/bgp_io.c
221
bgpd/bgp_io.c
@ -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
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
738
bgpd/bgp_route.c
738
bgpd/bgp_route.c
@ -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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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];
|
||||
|
||||
281
bgpd/bgp_vty.c
281
bgpd/bgp_vty.c
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
156
bgpd/bgpd.c
156
bgpd/bgpd.c
@ -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);
|
||||
|
||||
|
||||
73
bgpd/bgpd.h
73
bgpd/bgpd.h
@ -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
|
||||
|
||||
@ -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 ");
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
/*
|
||||
|
||||
@ -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++;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
26
configure.ac
26
configure.ac
@ -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 ---------------------
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
2142
doc/bgpd.texi
Normal file
File diff suppressed because it is too large
Load Diff
291
doc/install.texi
Normal file
291
doc/install.texi
Normal 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
433
doc/isisd.texi
Normal 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
930
doc/ospfd.texi
Normal 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
366
doc/pimd.texi
Normal 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
285
doc/routemap.texi
Normal 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.
|
||||
@ -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
|
||||
|
||||
|
||||
822
doc/user/vnc.rst
822
doc/user/vnc.rst
@ -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
1593
doc/vnc.texi
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
304
lib/frr_zmq.c
304
lib/frr_zmq.c
@ -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);
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
18
lib/if.c
18
lib/if.c
@ -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;
|
||||
|
||||
7
lib/if.h
7
lib/if.h
@ -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);
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -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
|
||||
|
||||
5
lib/ns.h
5
lib/ns.h
@ -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"
|
||||
|
||||
@ -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",
|
||||
|
||||
10
lib/prefix.h
10
lib/prefix.h
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
133
lib/ringbuf.c
Normal 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
125
lib/ringbuf.h
Normal 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_ */
|
||||
@ -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 \
|
||||
|
||||
14
lib/thread.c
14
lib/thread.c
@ -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);
|
||||
|
||||
19
lib/vrf.c
19
lib/vrf.c
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) \
|
||||
|
||||
@ -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
|
||||
|
||||
140
lib/zclient.c
140
lib/zclient.c
@ -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));
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
Loading…
Reference in New Issue
Block a user