Merge branch 'master' into evpn-session-vrf

This commit is contained in:
Tuetuopay 2019-03-28 18:41:38 +01:00 committed by GitHub
commit d074383c62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
241 changed files with 5515 additions and 3102 deletions

View File

@ -5,3 +5,4 @@
**/*.lo
**/*.so
**/.libs
docker/alpine/pkgs

View File

@ -175,13 +175,9 @@ EXTRA_DIST += \
python/clidef.py \
python/clippy/__init__.py \
\
redhat/frr.init \
redhat/frr.service \
redhat/daemons \
redhat/frr.logrotate \
redhat/frr.pam \
redhat/frr.spec \
redhat/README.rpm_build.md \
\
snapcraft/snapcraft.yaml \
snapcraft/README.snap_build.md \

View File

@ -9,13 +9,13 @@ license="GPL-2.0"
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
acct autoconf automake bash
binutils binutils-libs bison bsd-compat-headers build-base
binutils bison bsd-compat-headers build-base
c-ares c-ares-dev ca-certificates cryptsetup-libs curl
device-mapper-libs expat fakeroot flex fortify-headers gdbm
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
libgomp libisoburn libisofs libltdl libressl libssh2
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1
libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
patch pax-utils pcre perl pkgconf python2 python2-dev readline
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
source="$pkgname-$pkgver.tar.gz docker-start daemons"
source="$pkgname-$pkgver.tar.gz"
builddir="$srcdir"/$pkgname-$pkgver
@ -60,8 +60,7 @@ package() {
cd "$builddir"
make DESTDIR="$pkgdir" install
install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir
install -d "$pkgdir"/etc/init.d
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
}

View File

@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session);
/*
* Prototypes
*/
static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc);
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct sockaddr_any *local, bool mhop, const char *ifname,
const char *vrfname);
static uint32_t ptm_bfd_gen_ID(void);
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
@ -52,66 +54,47 @@ static void bs_down_handler(struct bfd_session *bs, int nstate);
static void bs_init_handler(struct bfd_session *bs, int nstate);
static void bs_up_handler(struct bfd_session *bs, int nstate);
/* Zeroed array with the size of an IPv6 address. */
struct in6_addr zero_addr;
/*
* Functions
*/
static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc)
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct sockaddr_any *local, bool mhop, const char *ifname,
const char *vrfname)
{
struct bfd_session_observer *bso;
struct bfd_session *bs = NULL;
bool is_shop, is_ipv4;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
bs = bso->bso_bs;
is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
/* Quick checks first. */
if (is_shop != (!bpc->bpc_mhop))
continue;
if (is_ipv4 != bpc->bpc_ipv4)
continue;
/*
* Slow lookup without hash because we don't have all
* information yet.
*/
if (is_shop) {
if (strcmp(bs->ifname, bpc->bpc_localif))
continue;
if (memcmp(&bs->shop.peer, &bpc->bpc_peer,
sizeof(bs->shop.peer)))
continue;
break;
}
if (strcmp(bs->vrfname, bpc->bpc_vrfname))
continue;
if (memcmp(&bs->mhop.peer, &bpc->bpc_peer,
sizeof(bs->mhop.peer)))
continue;
if (memcmp(&bs->mhop.local, &bpc->bpc_local,
sizeof(bs->mhop.local)))
continue;
memset(key, 0, sizeof(*key));
switch (peer->sa_sin.sin_family) {
case AF_INET:
key->family = AF_INET;
memcpy(&key->peer, &peer->sa_sin.sin_addr,
sizeof(peer->sa_sin.sin_addr));
memcpy(&key->local, &local->sa_sin.sin_addr,
sizeof(local->sa_sin.sin_addr));
break;
case AF_INET6:
key->family = AF_INET6;
memcpy(&key->peer, &peer->sa_sin6.sin6_addr,
sizeof(peer->sa_sin6.sin6_addr));
memcpy(&key->local, &local->sa_sin6.sin6_addr,
sizeof(local->sa_sin6.sin6_addr));
break;
}
if (bso == NULL)
bs = NULL;
return bs;
key->mhop = mhop;
if (ifname && ifname[0])
strlcpy(key->ifname, ifname, sizeof(key->ifname));
if (vrfname && vrfname[0])
strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
}
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bs;
struct peer_label *pl;
struct interface *ifp;
struct vrf *vrf;
struct bfd_mhop_key mhop;
struct bfd_shop_key shop;
struct bfd_key key;
/* Try to find label first. */
if (bpc->bpc_has_label) {
@ -123,38 +106,10 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
}
/* Otherwise fallback to peer/local hash lookup. */
if (bpc->bpc_mhop) {
memset(&mhop, 0, sizeof(mhop));
mhop.peer = bpc->bpc_peer;
mhop.local = bpc->bpc_local;
if (bpc->bpc_has_vrfname) {
vrf = vrf_lookup_by_name(bpc->bpc_vrfname);
if (vrf == NULL)
return NULL;
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
bpc->bpc_localif, bpc->bpc_vrfname);
mhop.vrfid = vrf->vrf_id;
}
bs = bfd_mhop_lookup(mhop);
} else {
memset(&shop, 0, sizeof(shop));
shop.peer = bpc->bpc_peer;
if (bpc->bpc_has_localif) {
ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif);
if (ifp == NULL)
return NULL;
shop.ifindex = ifp->ifindex;
}
bs = bfd_shop_lookup(shop);
}
if (bs != NULL)
return bs;
/* Search for entries that are incomplete. */
return bs_peer_waiting_find(bpc);
return bfd_key_lookup(key);
}
/*
@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
*/
int bfd_session_enable(struct bfd_session *bs)
{
struct sockaddr_in6 *sin6;
struct interface *ifp = NULL;
struct vrf *vrf = NULL;
int psock;
@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
* If the interface or VRF doesn't exist, then we must register
* the session but delay its start.
*/
if (bs->ifname[0] != 0) {
ifp = if_lookup_by_name_all_vrf(bs->ifname);
if (bs->key.ifname[0]) {
ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
if (ifp == NULL) {
log_error(
"session-enable: specified interface doesn't exists.");
@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs)
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf == NULL) {
log_error("session-enable: specified VRF doesn't exists.");
log_error(
"session-enable: specified VRF doesn't exists.");
return 0;
}
}
if (bs->vrfname[0] != 0) {
vrf = vrf_lookup_by_name(bs->vrfname);
if (bs->key.vrfname[0]) {
vrf = vrf_lookup_by_name(bs->key.vrfname);
if (vrf == NULL) {
log_error("session-enable: specified VRF doesn't exists.");
log_error(
"session-enable: specified VRF doesn't exists.");
return 0;
}
}
@ -202,26 +158,15 @@ int bfd_session_enable(struct bfd_session *bs)
if (bs->vrf == NULL)
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (bs->ifname[0] != 0 &&
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
if (bs->key.ifname[0]
&& BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
bs->ifp = ifp;
/* Set the IPv6 scope id for link-local addresses. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
sin6 = &bs->mhop.peer.sa_sin6;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
sin6->sin6_scope_id = bs->ifp != NULL
? bs->ifp->ifindex
: IFINDEX_INTERNAL;
sin6 = &bs->mhop.local.sa_sin6;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
sin6->sin6_scope_id = bs->ifp != NULL
? bs->ifp->ifindex
: IFINDEX_INTERNAL;
bs->local_ip.sa_sin6 = *sin6;
bs->local_address.sa_sin6 = *sin6;
/* Sanity check: don't leak open sockets. */
if (bs->sock != -1) {
zlog_debug("session-enable: previous socket open");
close(bs->sock);
bs->sock = -1;
}
/*
@ -232,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs)
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
psock = bp_peer_socket(bs);
if (psock == -1)
return -1;
return 0;
} else {
psock = bp_peer_socketv6(bs);
if (psock == -1)
return -1;
return 0;
}
/*
@ -247,25 +192,6 @@ int bfd_session_enable(struct bfd_session *bs)
bfd_recvtimer_update(bs);
ptm_bfd_start_xmt_timer(bs, false);
/* Registrate session into data structures. */
bs->discrs.my_discr = ptm_bfd_gen_ID();
bfd_id_insert(bs);
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
if (vrf != NULL)
bs->mhop.vrfid = vrf->vrf_id;
else
bs->mhop.vrfid = VRF_DEFAULT;
bfd_mhop_insert(bs);
} else {
if (ifp != NULL)
bs->shop.ifindex = ifp->ifindex;
else
bs->shop.ifindex = IFINDEX_INTERNAL;
bfd_shop_insert(bs);
}
return 0;
}
@ -288,13 +214,6 @@ void bfd_session_disable(struct bfd_session *bs)
bfd_echo_recvtimer_delete(bs);
bfd_xmttimer_delete(bs);
bfd_echo_xmttimer_delete(bs);
/* Unregister session from hashes to avoid unwanted activation. */
bfd_id_delete(bs->discrs.my_discr);
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
bfd_mhop_delete(bs->mhop);
else
bfd_shop_delete(bs->shop);
}
static uint32_t ptm_bfd_gen_ID(void)
@ -438,21 +357,20 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
if (bs == NULL)
return NULL;
/* Remove unused fields. */
switch (sa->sa_sin.sin_family) {
switch (bs->key.family) {
case AF_INET:
sa->sa_sin.sin_port = 0;
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
return bs;
if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
sizeof(sa->sa_sin.sin_addr)))
return NULL;
break;
case AF_INET6:
sa->sa_sin6.sin6_port = 0;
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
return bs;
if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
sizeof(sa->sa_sin6.sin6_addr)))
return NULL;
break;
}
return NULL;
return bs;
}
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
@ -461,32 +379,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
ifindex_t ifindex, vrf_id_t vrfid,
bool is_mhop)
{
struct bfd_session *l_bfd = NULL;
struct bfd_mhop_key mhop;
struct bfd_shop_key shop;
struct interface *ifp;
struct vrf *vrf;
struct bfd_key key;
/* Find our session using the ID signaled by the remote end. */
if (cp->discrs.remote_discr)
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
/* Search for session without using discriminator. */
if (is_mhop) {
memset(&mhop, 0, sizeof(mhop));
mhop.peer = *peer;
mhop.local = *local;
mhop.vrfid = vrfid;
ifp = if_lookup_by_index(ifindex, vrfid);
if (vrfid == VRF_DEFAULT) {
/*
* Don't use the default vrf, otherwise we won't find
* sessions that doesn't specify it.
*/
vrf = NULL;
} else
vrf = vrf_lookup_by_id(vrfid);
l_bfd = bfd_mhop_lookup(mhop);
} else {
memset(&shop, 0, sizeof(shop));
shop.peer = *peer;
shop.ifindex = ifindex;
l_bfd = bfd_shop_lookup(shop);
}
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
vrf ? vrf->name : NULL);
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
return l_bfd;
return bfd_key_lookup(key);
}
int bfd_xmt_cb(struct thread *t)
@ -701,6 +617,9 @@ static void bfd_session_free(struct bfd_session *bs)
bfd_session_disable(bs);
bfd_key_delete(bs->key);
bfd_id_delete(bs->discrs.my_discr);
/* Remove observer if any. */
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
if (bso->bso_bs != bs)
@ -743,29 +662,47 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
* start. See `bfd_session_enable` for more information.
*/
if (bpc->bpc_has_localif)
strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname));
strlcpy(bfd->key.ifname, bpc->bpc_localif,
sizeof(bfd->key.ifname));
if (bpc->bpc_has_vrfname)
strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
/* Add observer if we have moving parts. */
if (bfd->ifname[0] || bfd->vrfname[0])
bs_observer_add(bfd);
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
sizeof(bfd->key.vrfname));
/* Copy remaining data. */
if (bpc->bpc_ipv4 == false)
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
if (bpc->bpc_mhop) {
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
bfd->mhop.peer = bpc->bpc_peer;
bfd->mhop.local = bpc->bpc_local;
} else {
bfd->shop.peer = bpc->bpc_peer;
bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
switch (bfd->key.family) {
case AF_INET:
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr,
sizeof(bpc->bpc_local.sa_sin.sin_addr));
break;
case AF_INET6:
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr,
sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr,
sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
break;
default:
assert(1);
break;
}
bfd->local_ip = bpc->bpc_local;
bfd->local_address = bpc->bpc_local;
if (bpc->bpc_mhop)
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
bfd->key.mhop = bpc->bpc_mhop;
/* Registrate session into data structures. */
bfd_key_insert(bfd);
bfd->discrs.my_discr = ptm_bfd_gen_ID();
bfd_id_insert(bfd);
/* Try to enable session and schedule for packet receive/send. */
if (bfd_session_enable(bfd) == -1) {
@ -774,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
return NULL;
}
/* Add observer if we have moving parts. */
if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
bs_observer_add(bfd);
/* Apply other configurations. */
_bfd_session_update(bfd, bpc);
@ -1219,35 +1160,26 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen)
snprintf(buf, buflen, "%u second(s)", second);
}
const char *bs_to_string(struct bfd_session *bs)
const char *bs_to_string(const struct bfd_session *bs)
{
static char buf[256];
char addr_buf[INET6_ADDRSTRLEN];
int pos;
bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
pos += snprintf(buf + pos, sizeof(buf) - pos,
" peer:%s local:%s", satostr(&bs->mhop.peer),
satostr(&bs->mhop.local));
if (bs->mhop.vrfid != VRF_DEFAULT)
snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u",
bs->mhop.vrfid);
} else {
pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family)
pos += snprintf(buf + pos, sizeof(buf) - pos,
" local:%s",
satostr(&bs->local_address));
if (bs->shop.ifindex)
snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u",
bs->shop.ifindex);
}
pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
sizeof(addr_buf)));
if (bs->key.vrfname[0])
pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
bs->key.vrfname);
if (bs->key.ifname[0])
pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
bs->key.ifname);
return buf;
}
@ -1255,16 +1187,25 @@ int bs_observer_add(struct bfd_session *bs)
{
struct bfd_session_observer *bso;
bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
bso->bso_isaddress = false;
bso->bso_bs = bs;
bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
if (bso->bso_isinterface)
strlcpy(bso->bso_entryname, bs->ifname,
strlcpy(bso->bso_entryname, bs->key.ifname,
sizeof(bso->bso_entryname));
else
strlcpy(bso->bso_entryname, bs->vrfname,
strlcpy(bso->bso_entryname, bs->key.vrfname,
sizeof(bso->bso_entryname));
/* Handle socket binding failures caused by missing local addresses. */
if (bs->sock == -1) {
bso->bso_isaddress = true;
bso->bso_addr.family = bs->key.family;
memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
sizeof(bs->key.local));
}
TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
return 0;
@ -1276,21 +1217,59 @@ void bs_observer_del(struct bfd_session_observer *bso)
XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
}
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
{
memset(bpc, 0, sizeof(*bpc));
bpc->bpc_ipv4 = (bs->key.family == AF_INET);
bpc->bpc_mhop = bs->key.mhop;
switch (bs->key.family) {
case AF_INET:
bpc->bpc_peer.sa_sin.sin_family = AF_INET;
memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer,
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) {
bpc->bpc_local.sa_sin.sin_family = AF_INET6;
memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local,
sizeof(bpc->bpc_local.sa_sin.sin_addr));
}
break;
case AF_INET6:
bpc->bpc_peer.sa_sin.sin_family = AF_INET6;
memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer,
sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
bpc->bpc_local.sa_sin6.sin6_family = AF_INET6;
memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local,
sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
break;
}
if (bs->key.ifname[0]) {
bpc->bpc_has_localif = true;
strlcpy(bpc->bpc_localif, bs->key.ifname,
sizeof(bpc->bpc_localif));
}
if (bs->key.vrfname[0]) {
bpc->bpc_has_vrfname = true;
strlcpy(bpc->bpc_vrfname, bs->key.vrfname,
sizeof(bpc->bpc_vrfname));
}
}
/*
* BFD hash data structures to find sessions.
*/
static struct hash *bfd_id_hash;
static struct hash *bfd_shop_hash;
static struct hash *bfd_mhop_hash;
static struct hash *bfd_key_hash;
static unsigned int bfd_id_hash_do(void *p);
static unsigned int bfd_shop_hash_do(void *p);
static unsigned int bfd_mhop_hash_do(void *p);
static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop);
static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop);
static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop);
static unsigned int bfd_key_hash_do(void *p);
static void _bfd_free(struct hash_bucket *hb,
void *arg __attribute__((__unused__)));
@ -1311,73 +1290,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2)
}
/* BFD hash for single hop. */
static unsigned int bfd_shop_hash_do(void *p)
static unsigned int bfd_key_hash_do(void *p)
{
struct bfd_session *bs = p;
return jhash(&bs->shop, sizeof(bs->shop), 0);
return jhash(&bs->key, sizeof(bs->key), 0);
}
static bool bfd_shop_hash_cmp(const void *n1, const void *n2)
static bool bfd_key_hash_cmp(const void *n1, const void *n2)
{
const struct bfd_session *bs1 = n1, *bs2 = n2;
return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0;
}
/* BFD hash for multi hop. */
static unsigned int bfd_mhop_hash_do(void *p)
{
struct bfd_session *bs = p;
return jhash(&bs->mhop, sizeof(bs->mhop), 0);
}
static bool bfd_mhop_hash_cmp(const void *n1, const void *n2)
{
const struct bfd_session *bs1 = n1, *bs2 = n2;
return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0;
}
/* Helper functions */
static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop)
{
bs->shop = *shop;
/* Remove unused fields. */
switch (bs->shop.peer.sa_sin.sin_family) {
case AF_INET:
bs->shop.peer.sa_sin.sin_port = 0;
break;
case AF_INET6:
bs->shop.peer.sa_sin6.sin6_port = 0;
break;
}
}
static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop)
{
_shop_key(bs, shop);
bs->shop.ifindex = IFINDEX_INTERNAL;
}
static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop)
{
bs->mhop = *mhop;
/* Remove unused fields. */
switch (bs->mhop.peer.sa_sin.sin_family) {
case AF_INET:
bs->mhop.peer.sa_sin.sin_port = 0;
bs->mhop.local.sa_sin.sin_port = 0;
break;
case AF_INET6:
bs->mhop.peer.sa_sin6.sin6_port = 0;
bs->mhop.local.sa_sin6.sin6_port = 0;
break;
}
}
/*
* Hash public interface / exported functions.
@ -1393,34 +1319,35 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
return hash_lookup(bfd_id_hash, &bs);
}
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop)
struct bfd_session *bfd_key_lookup(struct bfd_key key)
{
struct bfd_session bs, *bsp;
_shop_key(&bs, &shop);
bs.key = key;
bsp = hash_lookup(bfd_key_hash, &bs);
bsp = hash_lookup(bfd_shop_hash, &bs);
if (bsp == NULL && bs.shop.ifindex != 0) {
/*
* Since the local interface spec is optional, try
* searching the key without it as well.
*/
_shop_key2(&bs, &shop);
bsp = hash_lookup(bfd_shop_hash, &bs);
/* Handle cases where local-address is optional. */
if (bsp == NULL && bs.key.family == AF_INET) {
memset(&bs.key.local, 0, sizeof(bs.key.local));
bsp = hash_lookup(bfd_key_hash, &bs);
}
/* Handle cases where ifname is optional. */
bs.key = key;
if (bsp == NULL && bs.key.ifname[0]) {
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
bsp = hash_lookup(bfd_key_hash, &bs);
/* Handle cases where local-address and ifname are optional. */
if (bsp == NULL && bs.key.family == AF_INET) {
memset(&bs.key.local, 0, sizeof(bs.key.local));
bsp = hash_lookup(bfd_key_hash, &bs);
}
}
return bsp;
}
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
{
struct bfd_session bs;
_mhop_key(&bs, &mhop);
return hash_lookup(bfd_mhop_hash, &bs);
}
/*
* Delete functions.
*
@ -1440,31 +1367,18 @@ struct bfd_session *bfd_id_delete(uint32_t id)
return hash_release(bfd_id_hash, &bs);
}
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop)
struct bfd_session *bfd_key_delete(struct bfd_key key)
{
struct bfd_session bs, *bsp;
_shop_key(&bs, &shop);
bsp = hash_release(bfd_shop_hash, &bs);
if (bsp == NULL && shop.ifindex != 0) {
/*
* Since the local interface spec is optional, try
* searching the key without it as well.
*/
_shop_key2(&bs, &shop);
bsp = hash_release(bfd_shop_hash, &bs);
bs.key = key;
bsp = hash_lookup(bfd_key_hash, &bs);
if (bsp == NULL && key.ifname[0]) {
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
bsp = hash_lookup(bfd_key_hash, &bs);
}
return bsp;
}
struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop)
{
struct bfd_session bs;
_mhop_key(&bs, &mhop);
return hash_release(bfd_mhop_hash, &bs);
return hash_release(bfd_key_hash, bsp);
}
/* Iteration functions. */
@ -1473,14 +1387,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg)
hash_iterate(bfd_id_hash, hif, arg);
}
void bfd_shop_iterate(hash_iter_func hif, void *arg)
void bfd_key_iterate(hash_iter_func hif, void *arg)
{
hash_iterate(bfd_shop_hash, hif, arg);
}
void bfd_mhop_iterate(hash_iter_func hif, void *arg)
{
hash_iterate(bfd_mhop_hash, hif, arg);
hash_iterate(bfd_key_hash, hif, arg);
}
/*
@ -1494,24 +1403,17 @@ bool bfd_id_insert(struct bfd_session *bs)
return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
}
bool bfd_shop_insert(struct bfd_session *bs)
bool bfd_key_insert(struct bfd_session *bs)
{
return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
}
bool bfd_mhop_insert(struct bfd_session *bs)
{
return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs);
}
void bfd_initialize(void)
{
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
"BFD discriminator hash");
bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
"BFD single hop hash");
bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
"BFD multihop hop hash");
"BFD session discriminator hash");
bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
"BFD session hash");
}
static void _bfd_free(struct hash_bucket *hb,
@ -1532,11 +1434,9 @@ void bfd_shutdown(void)
* assert() here to make sure it really happened.
*/
bfd_id_iterate(_bfd_free, NULL);
assert(bfd_shop_hash->count == 0);
assert(bfd_mhop_hash->count == 0);
assert(bfd_key_hash->count == 0);
/* Now free the hashes themselves. */
hash_free(bfd_id_hash);
hash_free(bfd_shop_hash);
hash_free(bfd_mhop_hash);
hash_free(bfd_key_hash);
}

View File

@ -173,15 +173,13 @@ enum bfd_session_flags {
#define BFD_CHECK_FLAG(field, flag) (field & flag)
/* BFD session hash keys */
struct bfd_shop_key {
struct sockaddr_any peer;
ifindex_t ifindex;
};
struct bfd_mhop_key {
struct sockaddr_any peer;
struct sockaddr_any local;
vrf_id_t vrfid;
struct bfd_key {
uint16_t family;
uint8_t mhop;
struct in6_addr peer;
struct in6_addr local;
char ifname[MAXNAMELEN];
char vrfname[MAXNAMELEN];
};
struct bfd_session_stats {
@ -227,19 +225,14 @@ struct bfd_session {
uint8_t polling;
/* This and the localDiscr are the keys to state info */
struct bfd_key key;
struct peer_label *pl;
union {
struct bfd_shop_key shop;
struct bfd_mhop_key mhop;
};
int sock;
struct sockaddr_any local_address;
struct sockaddr_any local_ip;
struct interface *ifp;
struct vrf *vrf;
char ifname[MAXNAMELEN];
char vrfname[MAXNAMELEN];
int sock;
/* BFD session flags */
enum bfd_session_flags flags;
@ -281,7 +274,11 @@ struct bfd_state_str_list {
struct bfd_session_observer {
struct bfd_session *bso_bs;
bool bso_isinterface;
char bso_entryname[MAXNAMELEN];
bool bso_isaddress;
union {
char bso_entryname[MAXNAMELEN];
struct prefix bso_addr;
};
TAILQ_ENTRY(bfd_session_observer) bso_entry;
};
@ -531,38 +528,28 @@ const char *satostr(struct sockaddr_any *sa);
const char *diag2str(uint8_t diag);
int strtosa(const char *addr, struct sockaddr_any *sa);
void integer2timestr(uint64_t time, char *buf, size_t buflen);
const char *bs_to_string(struct bfd_session *bs);
const char *bs_to_string(const struct bfd_session *bs);
int bs_observer_add(struct bfd_session *bs);
void bs_observer_del(struct bfd_session_observer *bso);
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
struct bfd_session *bfd_id_lookup(uint32_t id);
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop);
struct bfd_vrf *bfd_vrf_lookup(int vrf_id);
struct bfd_iface *bfd_iface_lookup(const char *ifname);
struct bfd_session *bfd_key_lookup(struct bfd_key key);
struct bfd_session *bfd_id_delete(uint32_t id);
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop);
struct bfd_vrf *bfd_vrf_delete(int vrf_id);
struct bfd_iface *bfd_iface_delete(const char *ifname);
struct bfd_session *bfd_key_delete(struct bfd_key key);
bool bfd_id_insert(struct bfd_session *bs);
bool bfd_shop_insert(struct bfd_session *bs);
bool bfd_mhop_insert(struct bfd_session *bs);
bool bfd_vrf_insert(struct bfd_vrf *vrf);
bool bfd_iface_insert(struct bfd_iface *iface);
bool bfd_key_insert(struct bfd_session *bs);
typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
void bfd_id_iterate(hash_iter_func hif, void *arg);
void bfd_shop_iterate(hash_iter_func hif, void *arg);
void bfd_mhop_iterate(hash_iter_func hif, void *arg);
void bfd_vrf_iterate(hash_iter_func hif, void *arg);
void bfd_iface_iterate(hash_iter_func hif, void *arg);
void bfd_key_iterate(hash_iter_func hif, void *arg);
/* Export callback functions for `event.c`. */
extern struct thread_master *master;
@ -572,6 +559,8 @@ int bfd_echo_recvtimer_cb(struct thread *t);
int bfd_xmt_cb(struct thread *t);
int bfd_echo_xmt_cb(struct thread *t);
extern struct in6_addr zero_addr;
/*
* bfdd_vty.c

View File

@ -79,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr));
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bs->ifp->ifindex;
sin6.sin6_port =
(port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@ -92,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
} else {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr));
sin.sin_port =
(port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@ -120,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
void ptm_bfd_echo_snd(struct bfd_session *bfd)
{
struct sockaddr_any *sa;
struct sockaddr *sa;
socklen_t salen;
int sd;
struct bfd_echo_pkt bep;
@ -135,31 +138,36 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
bep.len = BFD_ECHO_PKT_LEN;
bep.my_discr = htonl(bfd->discrs.my_discr);
sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer
: &bfd->shop.peer;
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
sd = bglobal.bg_echov6;
sin6 = sa->sa_sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bfd->ifp->ifindex;
sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sa = (struct sockaddr_any *)&sin6;
sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6);
} else {
sd = bglobal.bg_echo;
sin = sa->sa_sin;
memset(&sin6, 0, sizeof(sin6));
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
sin.sin_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sa = (struct sockaddr_any *)&sin;
sa = (struct sockaddr *)&sin;
salen = sizeof(sin);
}
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
(struct sockaddr *)sa, salen)
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
salen)
== -1)
return;
@ -602,8 +610,8 @@ int bfd_recv_cb(struct thread *t)
bfd->mh_ttl, BFD_TTL_VAL);
return 0;
}
} else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
bfd->local_ip = local;
} else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
bfd->local_address = local;
}
/*
@ -917,25 +925,26 @@ int bp_peer_socket(const struct bfd_session *bs)
return -1;
}
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
if (bs->key.ifname[0]) {
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd);
return -1;
}
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
bs->mhop.vrfid != VRF_DEFAULT) {
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
&& bs->key.vrfname[0]) {
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd);
return -1;
}
}
/* Find an available source port in the proper range */
sin = bs->local_ip.sa_sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
sin.sin_addr.s_addr = INADDR_ANY;
@ -987,20 +996,23 @@ int bp_peer_socketv6(const struct bfd_session *bs)
}
/* Find an available source port in the proper range */
sin6 = bs->local_ip.sa_sin6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr));
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bs->ifp->ifindex;
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
if (bs->key.ifname[0]) {
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd);
return -1;
}
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
bs->mhop.vrfid != VRF_DEFAULT) {
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
&& bs->key.vrfname[0]) {
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd);
return -1;
}

View File

@ -79,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
const char *local_str, const char *ifname,
const char *vrfname);
/*
* Commands definition.
*/
@ -369,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
*/
static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
{
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
char addr_buf[INET6_ADDRSTRLEN];
vty_out(vty, "\tpeer %s",
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
vty_out(vty, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
if (bs->vrfname[0])
vty_out(vty, " vrf %s", bs->vrfname);
vty_out(vty, "\n");
} else {
vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
vty_out(vty, " local-address %s",
satostr(&bs->local_address));
if (bs->ifname[0])
vty_out(vty, " interface %s", bs->ifname);
vty_out(vty, "\n");
}
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
vty_out(vty, " local-address %s",
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
sizeof(addr_buf)));
if (bs->key.vrfname[0])
vty_out(vty, " vrf %s", bs->key.vrfname);
if (bs->key.ifname[0])
vty_out(vty, " interface %s", bs->key.ifname);
vty_out(vty, "\n");
if (bs->pl)
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
@ -453,22 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
static struct json_object *_peer_json_header(struct bfd_session *bs)
{
struct json_object *jo = json_object_new_object();
char addr_buf[INET6_ADDRSTRLEN];
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
if (bs->key.mhop)
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
if (bs->vrfname[0])
json_object_string_add(jo, "vrf", bs->vrfname);
} else {
else
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
json_object_string_add(jo, "local",
satostr(&bs->local_address));
if (bs->ifname[0])
json_object_string_add(jo, "interface", bs->ifname);
}
json_object_string_add(jo, "peer",
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
json_object_string_add(jo, "local",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf", bs->key.vrfname);
if (bs->key.ifname[0])
json_object_string_add(jo, "interface", bs->key.ifname);
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
@ -916,25 +921,29 @@ static int bfdd_write_config(struct vty *vty)
static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
{
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
char addr_buf[INET6_ADDRSTRLEN];
vty_out(vty, " peer %s",
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
if (bs->key.mhop)
vty_out(vty, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
if (bs->vrfname[0])
vty_out(vty, " vrf %s", bs->vrfname);
vty_out(vty, "\n");
} else {
vty_out(vty, " peer %s", satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
vty_out(vty, " local-address %s",
satostr(&bs->local_address));
if (bs->ifname[0])
vty_out(vty, " interface %s", bs->ifname);
vty_out(vty, "\n");
}
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
vty_out(vty, " local-address %s",
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
sizeof(addr_buf)));
if (bs->key.vrfname[0])
vty_out(vty, " vrf %s", bs->key.vrfname);
if (bs->key.ifname[0])
vty_out(vty, " interface %s", bs->key.ifname);
vty_out(vty, "\n");
if (bs->sock == -1)
vty_out(vty, " ! vrf or interface doesn't exist\n");
vty_out(vty,
" ! vrf, interface or local-address doesn't exist\n");
if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
@ -980,16 +989,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
static int bfdd_peer_write_config(struct vty *vty)
{
struct bfd_session_observer *bso;
bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
/* Only print disabled sessions here. */
if (bso->bso_bs->sock != -1)
continue;
_bfdd_peer_write_config(vty, bso->bso_bs);
}
return 1;
}

View File

@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo,
log_debug("\tpeer-label: %s", sval);
/* Translate the label into BFD address keys. */
bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH);
if (bpc->bpc_mhop) {
bpc->bpc_peer = pl->pl_bs->mhop.peer;
bpc->bpc_local = pl->pl_bs->mhop.local;
if (pl->pl_bs->mhop.vrfid != VRF_DEFAULT) {
bpc->bpc_has_vrfname = true;
strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name,
sizeof(bpc->bpc_vrfname));
}
} else {
bpc->bpc_peer = pl->pl_bs->shop.peer;
if (pl->pl_bs->ifname[0]) {
bpc->bpc_has_localif = true;
strlcpy(bpc->bpc_localif, pl->pl_bs->ifname,
sizeof(bpc->bpc_localif));
}
}
bs_to_bpc(pl->pl_bs, bpc);
return 0;
}
@ -519,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
{
char addr_buf[INET6_ADDRSTRLEN];
/* Add peer 'key' information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
json_object_boolean_true_add(jo, "ipv6");
@ -528,21 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
satostr(&bs->mhop.peer));
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "local-address",
satostr(&bs->mhop.local));
if (bs->vrfname[0])
json_object_string_add(jo, "vrf-name", bs->vrfname);
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
satostr(&bs->shop.peer));
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
json_object_string_add(jo, "local-address",
satostr(&bs->local_address));
if (bs->ifname[0])
inet_ntop(bs->key.family, &bs->key.peer,
addr_buf, sizeof(addr_buf)));
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
json_object_string_add(
jo, "local-address",
inet_ntop(bs->key.family, &bs->key.local,
addr_buf, sizeof(addr_buf)));
if (bs->key.ifname[0])
json_object_string_add(jo, "local-interface",
bs->ifname);
bs->key.ifname);
}
if (bs->pl)

View File

@ -55,7 +55,7 @@ static struct zclient *zclient;
/*
* Prototypes
*/
static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa);
static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
static int _ptm_msg_read(struct stream *msg, int command,
@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line,
#define DEBUG_PRINTBPC(bpc)
#endif /* BFD_DEBUG */
static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
{
switch (sa->sa_sin.sin_family) {
stream_putc(msg, family);
switch (family) {
case AF_INET:
stream_putc(msg, sa->sa_sin.sin_family);
stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
stream_put(msg, addr, sizeof(struct in_addr));
stream_putc(msg, 32);
break;
case AF_INET6:
stream_putc(msg, sa->sa_sin6.sin6_family);
stream_put(msg, &sa->sa_sin6.sin6_addr,
sizeof(sa->sa_sin6.sin6_addr));
stream_put(msg, addr, sizeof(struct in6_addr));
stream_putc(msg, 128);
break;
default:
return -1;
assert(0);
break;
}
return 0;
@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
int ptm_bfd_notify(struct bfd_session *bs)
{
struct stream *msg;
struct sockaddr_any sac;
bs->stats.znotification++;
@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
stream_putl(msg, IFINDEX_INTERNAL);
/* BFD destination prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
_ptm_msg_address(msg, &bs->mhop.peer);
else
_ptm_msg_address(msg, &bs->shop.peer);
_ptm_msg_address(msg, bs->key.family, &bs->key.peer);
/* BFD status */
switch (bs->ses_state) {
@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
}
/* BFD source prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
_ptm_msg_address(msg, &bs->mhop.local);
} else {
if (bs->local_address.sa_sin.sin_family)
_ptm_msg_address(msg, &bs->local_address);
else if (bs->local_address.sa_sin.sin_family)
_ptm_msg_address(msg, &bs->local_ip);
else {
sac = bs->shop.peer;
switch (sac.sa_sin.sin_family) {
case AF_INET:
memset(&sac.sa_sin.sin_addr, 0,
sizeof(sac.sa_sin.sin_family));
break;
case AF_INET6:
memset(&sac.sa_sin6.sin6_addr, 0,
sizeof(sac.sa_sin6.sin6_family));
break;
default:
assert(false);
break;
}
/* No local address found yet, so send zeroes. */
_ptm_msg_address(msg, &sac);
}
}
_ptm_msg_address(msg, bs->key.family, &bs->key.local);
/* Write packet size. */
stream_putw_at(msg, 0, stream_get_endp(msg));
@ -290,7 +259,6 @@ stream_failure:
static int _ptm_msg_read(struct stream *msg, int command,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
struct interface *ifp;
uint32_t pid;
uint8_t ttl __attribute__((unused));
size_t ifnamelen;
@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command,
if (bpc->bpc_has_localif) {
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
bpc->bpc_localif[ifnamelen] = 0;
/*
* IPv6 link-local addresses must use scope id,
* otherwise the session lookup will always fail
* and we'll have multiple sessions showing up.
*
* This problem only happens with single hop
* since it is not possible to have link-local
* address for multi hop sessions.
*/
if (bpc->bpc_ipv4 == false
&& IN6_IS_ADDR_LINKLOCAL(
&bpc->bpc_peer.sa_sin6.sin6_addr)) {
ifp = if_lookup_by_name_all_vrf(
bpc->bpc_localif);
if (ifp == NULL) {
log_error(
"ptm-read: interface %s doesn't exists",
bpc->bpc_localif);
return -1;
}
bpc->bpc_peer.sa_sin6.sin6_scope_id =
ifp->ifindex;
}
}
}
@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
/* Interface name mismatch. */
bs = bso->bso_bs;
if (strcmp(ifp->name, bs->ifname))
if (strcmp(ifp->name, bs->key.ifname))
continue;
/* Skip enabled sessions. */
if (bs->sock != -1)
@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
/* Interface name mismatch. */
bs = bso->bso_bs;
if (strcmp(ifp->name, bs->ifname))
if (strcmp(ifp->name, bs->key.ifname))
continue;
/* Skip disabled sessions. */
if (bs->sock == -1)
@ -691,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)),
return 0;
}
static void bfdd_sessions_enable_address(struct connected *ifc)
{
struct bfd_session_observer *bso;
struct bfd_session *bs;
struct prefix prefix;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
if (bso->bso_isaddress == false)
continue;
/* Skip enabled sessions. */
bs = bso->bso_bs;
if (bs->sock != -1)
continue;
/* Check address. */
prefix = bso->bso_addr;
prefix.prefixlen = ifc->address->prefixlen;
if (prefix_cmp(&prefix, ifc->address))
continue;
/* Try to enable it. */
bfd_session_enable(bs);
}
}
static int bfdd_interface_address_update(int cmd, struct zclient *zc,
zebra_size_t len
__attribute__((__unused__)),
vrf_id_t vrfid)
{
struct connected *ifc;
ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid);
if (ifc == NULL)
return 0;
bfdd_sessions_enable_address(ifc);
return 0;
}
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
zclient = zclient_new(master, &zclient_options_default);
@ -713,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
/* Learn about interface VRF. */
zclient->interface_vrf_update = bfdd_interface_vrf_update;
/* Learn about new addresses being registered. */
zclient->interface_address_add = bfdd_interface_address_update;
zclient->interface_address_delete = bfdd_interface_address_update;
}
void bfdd_zclient_stop(void)

View File

@ -384,7 +384,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
}
}
zlog_info("Resetting peer %s%s due to change in addpath config\n",
zlog_info("Resetting peer %s%s due to change in addpath config",
CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
peer->host);

View File

@ -1715,7 +1715,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
if (!peer->nexthop.ifp) {
zlog_warn("%s: interface not set appropriately to handle some attributes",
zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing",
peer->host);
return BGP_ATTR_PARSE_WITHDRAW;
}
@ -1732,7 +1732,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
if (!peer->nexthop.ifp) {
zlog_warn("%s: interface not set appropriately to handle some attributes",
zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing",
peer->host);
return BGP_ATTR_PARSE_WITHDRAW;
}
@ -1762,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
}
if (!peer->nexthop.ifp) {
zlog_warn("%s: Interface not set appropriately to handle this some attributes",
zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing",
peer->host);
return BGP_ATTR_PARSE_WITHDRAW;
}

View File

@ -48,6 +48,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
/*
* Definitions and external declarations.
@ -2503,6 +2504,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
/* Perform route selection and update zebra, if required. */
bgp_process(bgp_vrf, rn, afi, safi);
/* Process for route leaking. */
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
return ret;
}
@ -2668,6 +2672,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
if (!pi)
return 0;
/* Process for route leaking. */
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
/* Mark entry for deletion */
@ -2940,6 +2947,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
return 0;
}
/* This API will scan evpn routes for checking attribute's rmac
* macthes with bgp instance router mac. It avoid installing
* route into bgp vrf table and remote rmac in bridge table.
*/
static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
struct prefix_evpn *evp,
struct bgp_path_info *pi)
{
/* evpn route could have learnt prior to L3vni has come up,
* perform rmac check before installing route and
* remote router mac.
* The route will be removed from global bgp table once
* SVI comes up with MAC and stored in hash, triggers
* bgp_mac_rescan_all_evpn_tables.
*/
if (pi->attr &&
memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
char buf1[PREFIX_STRLEN];
char attr_str[BUFSIZ] = {0};
bgp_dump_attr(pi->attr, attr_str, BUFSIZ);
zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac",
__func__, bgp_vrf->vrf_id,
prefix2str(evp, buf1, sizeof(buf1)),
attr_str);
}
return 1;
}
return 0;
}
/*
* Install or uninstall mac-ip routes are appropriate for this
* particular VRF.
@ -2996,6 +3038,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
continue;
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
if (bgp_evpn_route_rmac_self_check(
bgp_vrf, evp, pi))
continue;
if (install)
ret = install_evpn_route_entry_in_vrf(
bgp_vrf, evp, pi);
@ -4223,11 +4269,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
table = bgp_vrf->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
/* Only care about "selected" routes - non-imported. */
/* Only care about "selected" routes. Also ensure that
* these are routes that are injectable into EVPN.
*/
/* TODO: Support for AddPath for EVPN. */
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& (!pi->extra || !pi->extra->parent)) {
&& is_route_injectable_into_evpn(pi)) {
bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
afi, safi);
break;
@ -4294,12 +4342,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
table = bgp_vrf->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
/* Need to identify the "selected" route entry to use its
* attribute. Also, we only consider "non-imported" routes.
* attribute. Also, ensure that the route is injectable
* into EVPN.
* TODO: Support for AddPath for EVPN.
*/
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& (!pi->extra || !pi->extra->parent)) {
&& is_route_injectable_into_evpn(pi)) {
/* apply the route-map */
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
@ -5033,6 +5082,9 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
*/
void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
{
if (is_vrf_rd_configured(bgp))
return;
form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd);
}

View File

@ -89,8 +89,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
!ri->extra->parent)
return 0;
/* See if the parent is of family L2VPN/EVPN */
parent_ri = (struct bgp_path_info *)ri->extra->parent;
/* Determine parent recursively */
for (parent_ri = ri->extra->parent;
parent_ri->extra && parent_ri->extra->parent;
parent_ri = parent_ri->extra->parent)
;
/* See if of family L2VPN/EVPN */
rn = parent_ri->net;
if (!rn)
return 0;
@ -102,6 +107,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
return 0;
}
/* Flag if the route path's family is EVPN. */
static inline bool is_pi_family_evpn(struct bgp_path_info *pi)
{
return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN);
}
/* Flag if the route is injectable into EVPN. This would be either a
* non-imported route or a non-EVPN imported route.
*/
static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
{
struct bgp_path_info *parent_pi;
struct bgp_table *table;
struct bgp_node *rn;
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
!pi->extra ||
!pi->extra->parent)
return true;
parent_pi = (struct bgp_path_info *)pi->extra->parent;
rn = parent_pi->net;
if (!rn)
return true;
table = bgp_node_table(rn);
if (table &&
table->afi == AFI_L2VPN &&
table->safi == SAFI_EVPN)
return false;
return true;
}
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
struct prefix *p,
struct attr *src_attr, afi_t afi,

View File

@ -30,8 +30,9 @@
#define RT_ADDRSTRLEN 28
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
#define EVPN_ROUTE_PREFIXLEN 224
/* EVPN prefix lengths. This represents the sizeof struct evpn_addr
* in bits */
#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8)
/* EVPN route types. */
typedef enum {

View File

@ -3369,7 +3369,8 @@ DEFUN (bgp_evpn_advertise_type5,
}
/* advertise type-5 routes */
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
if (advertise_type5_routes(bgp_vrf, afi))
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
return CMD_SUCCESS;
}
@ -5222,7 +5223,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
vty_out(vty, " default-originate ipv6\n");
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
vty_out(vty, " rd %s\n",
vty_out(vty, " rd %s\n",
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
/* import route-target */

View File

@ -310,7 +310,8 @@ void bgp_timer_set(struct peer *peer)
status start timer is on unless peer is shutdown or peer is
inactive. All other timer must be turned off */
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
|| peer->bgp->vrf_id == VRF_UNKNOWN) {
|| (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
peer->bgp->vrf_id == VRF_UNKNOWN)) {
BGP_TIMER_OFF(peer->t_start);
} else {
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer)
return 0;
}
if (peer->bgp->vrf_id == VRF_UNKNOWN) {
if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
peer->bgp->vrf_id == VRF_UNKNOWN) {
if (bgp_debug_neighbor_events(peer))
flog_err(
EC_BGP_FSM,

View File

@ -284,9 +284,9 @@ static int bgp_vrf_enable(struct vrf *vrf)
bgp_vrf_link(bgp, vrf);
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
/* Update any redistribute vrf bitmaps if the vrf_id changed */
/* Update any redistribution if vrf_id changed */
if (old_vrf_id != bgp->vrf_id)
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
bgp_redistribute_redo(bgp);
bgp_instance_up(bgp);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
@ -333,9 +333,9 @@ static int bgp_vrf_disable(struct vrf *vrf)
/* We have instance configured, unlink from VRF and make it
* "down". */
bgp_vrf_unlink(bgp, vrf);
/* Update any redistribute vrf bitmaps if the vrf_id changed */
/* Delete any redistribute vrf bitmaps if the vrf_id changed */
if (old_vrf_id != bgp->vrf_id)
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id);
bgp_instance_down(bgp);
}

View File

@ -46,6 +46,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_evpn.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (bpi->extra && bpi->extra->bgp_orig)
bgp_nexthop = bpi->extra->bgp_orig;
/* No nexthop tracking for redistributed routes */
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
/*
* No nexthop tracking for redistributed routes or for
* EVPN-imported routes that get leaked.
*/
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
is_pi_family_evpn(bpi_ultimate))
nh_valid = 1;
else
/*
@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
* No nexthop tracking for redistributed routes because
* their originating protocols will do the tracking and
* withdraw those routes if the nexthops become unreachable
* This also holds good for EVPN-imported routes that get
* leaked.
*/
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
is_pi_family_evpn(bpi_ultimate))
nh_valid = 1;
else
/*
@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
return;
}
/* loop check - should not be an imported route. */
if (path_vrf->extra && path_vrf->extra->bgp_orig)
/* Is this route exportable into the VPN table? */
if (!is_route_injectable_into_vpn(path_vrf))
return;
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: %s skipping: %s", __func__,
@ -894,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
path_vrf->type, path_vrf->sub_type);
}
if (path_vrf->sub_type != BGP_ROUTE_NORMAL
&& path_vrf->sub_type != BGP_ROUTE_STATIC
&& path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) {
if (debug)
zlog_debug("%s: wrong sub_type %d", __func__,
path_vrf->sub_type);
return;
}
if (!bgp_vpn)
return;
@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
return;
}
/* Is this route exportable into the VPN table? */
if (!is_route_injectable_into_vpn(path_vrf))
return;
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
@ -995,7 +997,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
== bgp_vrf) {
/* delete route */
if (debug)
zlog_debug("%s: deleting it\n",
zlog_debug("%s: deleting it",
__func__);
bgp_aggregate_decrement(bgp_vpn, &bn->p,
bpi, afi, safi);
@ -1352,7 +1354,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) {
if (bpi->extra
&& bpi->extra->bgp_orig != bgp_vrf
&& bpi->extra->parent
&& is_pi_family_vpn(bpi->extra->parent)) {
/* delete route */
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,

View File

@ -226,6 +226,39 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
}
}
/* Flag if the route is injectable into VPN. This would be either a
* non-imported route or a non-VPN imported route.
*/
static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi)
{
struct bgp_path_info *parent_pi;
struct bgp_table *table;
struct bgp_node *rn;
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
!pi->extra ||
!pi->extra->parent)
return true;
parent_pi = (struct bgp_path_info *)pi->extra->parent;
rn = parent_pi->net;
if (!rn)
return true;
table = bgp_node_table(rn);
if (table &&
(table->afi == AFI_IP || table->afi == AFI_IP6) &&
table->safi == SAFI_MPLS_VPN)
return false;
return true;
}
/* Flag if the route path's family is VPN. */
static inline bool is_pi_family_vpn(struct bgp_path_info *pi)
{
return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) ||
is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN));
}
extern void vpn_policy_routemap_event(const char *rmap_name);
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);

View File

@ -2476,8 +2476,9 @@ 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 (advertise_type5_routes(bgp, afi) && new_select &&
(!new_select->extra || !new_select->extra->parent)) {
if (advertise_type5_routes(bgp, afi) &&
new_select &&
is_route_injectable_into_evpn(new_select)) {
/* apply the route-map */
if (bgp->adv_cmd_rmap[afi][safi].map) {
@ -2500,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
afi, safi);
}
} else if (advertise_type5_routes(bgp, afi) && old_select &&
(!old_select->extra || !old_select->extra->parent))
} else if (advertise_type5_routes(bgp, afi) &&
old_select &&
is_route_injectable_into_evpn(old_select))
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
}

View File

@ -409,6 +409,24 @@ static inline int bgp_fibupd_safi(safi_t safi)
return 0;
}
/* Flag if the route path's family matches params. */
static inline bool is_pi_family_matching(struct bgp_path_info *pi,
afi_t afi, safi_t safi)
{
struct bgp_table *table;
struct bgp_node *rn;
rn = pi->net;
if (!rn)
return false;
table = bgp_node_table(rn);
if (table &&
table->afi == afi &&
table->safi == safi)
return true;
return false;
}
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi);

View File

@ -3368,7 +3368,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
"Processing route_map %s update on advertise type5 route command",
rmap_name);
if (route_update) {
if (route_update && advertise_type5_routes(bgp, afi)) {
bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
bgp_evpn_advertise_type5_routes(bgp, afi, safi);
}

View File

@ -125,7 +125,7 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
static struct cache *find_cache(const uint8_t preference);
static int add_tcp_cache(const char *host, const char *port,
const uint8_t preference);
static void print_record(const struct pfx_record *record, void *data);
static void print_record(const struct pfx_record *record, struct vty *vty);
static int is_synchronized(void);
static int is_running(void);
static void route_match_free(void *rule);
@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference)
return NULL;
}
static void print_record(const struct pfx_record *record, void *data)
static void print_record(const struct pfx_record *record, struct vty *vty)
{
char ip[INET6_ADDRSTRLEN];
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
record->max_len, record->asn);
}
static void print_record_cb(const struct pfx_record *record, void *data)
{
struct rpki_for_each_record_arg *arg = data;
struct vty *vty = arg->vty;
(*arg->prefix_amount)++;
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
record->max_len, record->asn);
print_record(record, vty);
}
static struct rtr_mgr_group *get_groups(void)
@ -663,10 +669,10 @@ static void print_prefix_table(struct vty *vty)
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
arg.prefix_amount = &number_of_ipv4_prefixes;
pfx_table_for_each_ipv4_record(pfx_table, print_record, &arg);
pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
arg.prefix_amount = &number_of_ipv6_prefixes;
pfx_table_for_each_ipv6_record(pfx_table, print_record, &arg);
pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes);
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
@ -1179,6 +1185,58 @@ DEFUN (show_rpki_prefix_table,
return CMD_SUCCESS;
}
DEFPY (show_rpki_prefix,
show_rpki_prefix_cmd,
"show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup IP prefix and optionally ASN in prefix table\n"
"IPv4 prefix\n"
"IPv6 prefix\n"
"AS Number\n")
{
if (!is_synchronized()) {
vty_out(vty, "No Conection to RPKI cache server.\n");
return CMD_WARNING;
}
struct lrtr_ip_addr addr;
char addr_str[INET6_ADDRSTRLEN];
size_t addr_len = strchr(prefix_str, '/') - prefix_str;
memset(addr_str, 0, sizeof(addr_str));
memcpy(addr_str, prefix_str, addr_len);
if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
vty_out(vty, "Invalid IP prefix\n");
return CMD_WARNING;
}
struct pfx_record *matches = NULL;
unsigned int match_count = 0;
enum pfxv_state result;
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
asn, &addr, prefix->prefixlen, &result)
!= PFX_SUCCESS) {
vty_out(vty, "Prefix lookup failed");
return CMD_WARNING;
}
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
for (size_t i = 0; i < match_count; ++i) {
const struct pfx_record *record = &matches[i];
if (record->max_len >= prefix->prefixlen
&& ((asn != 0 && asn == record->asn) || asn == 0)) {
print_record(&matches[i], vty);
}
}
return CMD_SUCCESS;
}
DEFUN (show_rpki_cache_server,
show_rpki_cache_server_cmd,
"show rpki cache-server",
@ -1450,6 +1508,7 @@ static void install_cli_commands(void)
install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd);
install_element(ENABLE_NODE, &show_rpki_cache_connection_cmd);
install_element(ENABLE_NODE, &show_rpki_cache_server_cmd);
install_element(ENABLE_NODE, &show_rpki_prefix_cmd);
/* Install debug commands */
install_element(CONFIG_NODE, &debug_rpki_cmd);

View File

@ -2055,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw,
return CMD_SUCCESS;
}
static void bgp_redistribute_redo(struct bgp *bgp)
{
afi_t afi;
int i;
struct list *red_list;
struct listnode *node;
struct bgp_redist *red;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
red_list = bgp->redist[afi][i];
if (!red_list)
continue;
for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
bgp_redistribute_resend(bgp, afi, i,
red->instance);
}
}
}
}
/* "bgp graceful-shutdown" configuration */
DEFUN (bgp_graceful_shutdown,
bgp_graceful_shutdown_cmd,
@ -2841,18 +2818,23 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
as = strtoul(as_str, NULL, 10);
}
/* If peer is peer group, call proper function. */
/* If peer is peer group or interface peer, call proper function. */
ret = str2sockunion(peer_str, &su);
if (ret < 0) {
/* Check for peer by interface */
struct peer *peer;
/* Check if existing interface peer */
peer = peer_lookup_by_conf_if(bgp, peer_str);
ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi,
safi);
if (ret < 0) {
/* if not interface peer, check peer-group settings */
if (ret < 0 && !peer) {
ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
if (ret < 0) {
vty_out(vty,
"%% Create the peer-group or interface first or specify \"interface\" keyword\n");
vty_out(vty, "%% if using an unnumbered interface neighbor\n");
"%% Create the peer-group or interface first\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
@ -3251,7 +3233,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
/* look up for neighbor by interface name config. */
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
if (peer) {
peer_as_change(peer, 0, AS_SPECIFIED);
peer_as_change(peer, 0, AS_UNSPECIFIED);
return CMD_SUCCESS;
}
@ -8031,7 +8013,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json, "ribMemory",
ents * sizeof(struct bgp_node));
ents = listcount(bgp->peer);
ents = bgp->af_peer_count[afi][safi];
json_object_int_add(json, "peerCount", ents);
json_object_int_add(json, "peerMemory",
ents * sizeof(struct peer));
@ -8071,7 +8053,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
bgp_node)));
/* Peer related usage */
ents = listcount(bgp->peer);
ents = bgp->af_peer_count[afi][safi];
vty_out(vty, "Peers %ld, using %s of memory\n",
ents,
mtype_memstr(
@ -8522,7 +8504,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi)
}
/* Show BGP peer's information. */
enum show_type { show_all, show_peer };
enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
afi_t afi, safi_t safi,
@ -10945,6 +10927,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
struct peer *peer;
int find = 0;
bool nbr_output = false;
afi_t afi = AFI_MAX;
safi_t safi = SAFI_MAX;
if (type == show_ipv4_peer || type == show_ipv4_all) {
afi = AFI_IP;
} else if (type == show_ipv6_peer || type == show_ipv6_all) {
afi = AFI_IP6;
}
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
@ -10973,17 +10963,54 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
}
}
break;
case show_ipv4_peer:
case show_ipv6_peer:
FOREACH_SAFI (safi) {
if (peer->afc[afi][safi]) {
if (conf_if) {
if ((peer->conf_if
&& !strcmp(peer->conf_if, conf_if))
|| (peer->hostname
&& !strcmp(peer->hostname, conf_if))) {
find = 1;
bgp_show_peer(vty, peer, use_json,
json);
break;
}
} else {
if (sockunion_same(&peer->su, su)) {
find = 1;
bgp_show_peer(vty, peer, use_json,
json);
break;
}
}
}
}
break;
case show_ipv4_all:
case show_ipv6_all:
FOREACH_SAFI (safi) {
if (peer->afc[afi][safi]) {
bgp_show_peer(vty, peer, use_json, json);
nbr_output = true;
break;
}
}
break;
}
}
if (type == show_peer && !find) {
if ((type == show_peer || type == show_ipv4_peer ||
type == show_ipv6_peer) && !find) {
if (use_json)
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
else
vty_out(vty, "%% No such neighbor in this view/vrf\n");
}
if (type != show_peer && !nbr_output && !use_json)
if (type != show_peer && type != show_ipv4_peer &&
type != show_ipv6_peer && !nbr_output && !use_json)
vty_out(vty, "%% No BGP neighbors found\n");
if (use_json) {
@ -11049,7 +11076,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
: bgp->name);
}
if (type == show_peer) {
if (type == show_peer || type == show_ipv4_peer ||
type == show_ipv6_peer) {
ret = str2sockunion(ip_str, &su);
if (ret < 0)
bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
@ -11058,7 +11086,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
bgp_show_neighbor(vty, bgp, type, &su, NULL,
use_json, json);
} else {
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
bgp_show_neighbor(vty, bgp, type, NULL, NULL,
use_json, json);
}
json_object_free(json);
@ -11151,6 +11179,7 @@ DEFUN (show_ip_bgp_neighbors,
char *vrf = NULL;
char *sh_arg = NULL;
enum show_type sh_type;
afi_t afi = AFI_MAX;
bool uj = use_json(argc, argv);
@ -11166,13 +11195,29 @@ DEFUN (show_ip_bgp_neighbors,
vrf = argv[idx + 1]->arg;
idx++;
if (argv_find(argv, argc, "ipv4", &idx)) {
sh_type = show_ipv4_all;
afi = AFI_IP;
} else if (argv_find(argv, argc, "ipv6", &idx)) {
sh_type = show_ipv6_all;
afi = AFI_IP6;
} else {
sh_type = show_all;
}
if (argv_find(argv, argc, "A.B.C.D", &idx)
|| argv_find(argv, argc, "X:X::X:X", &idx)
|| argv_find(argv, argc, "WORD", &idx)) {
sh_type = show_peer;
sh_arg = argv[idx]->arg;
} else
sh_type = show_all;
}
if (sh_type == show_peer && afi == AFI_IP) {
sh_type = show_ipv4_peer;
} else if (sh_type == show_peer && afi == AFI_IP6) {
sh_type = show_ipv6_peer;
}
return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj);
}
@ -11267,8 +11312,9 @@ DEFUN (show_ip_bgp_attr_info,
return CMD_SUCCESS;
}
static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, bool use_json)
static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
afi_t afi, safi_t safi,
bool use_json, json_object *json)
{
struct bgp *bgp;
struct listnode *node;
@ -11277,13 +11323,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
char *ecom_str;
vpn_policy_direction_t dir;
if (use_json) {
json_object *json = NULL;
if (json) {
json_object *json_import_vrfs = NULL;
json_object *json_export_vrfs = NULL;
json = json_object_new_object();
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
if (!bgp) {
@ -11354,11 +11397,12 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
if (use_json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
json_object_free(json);
}
} else {
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
@ -11422,6 +11466,54 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
return CMD_SUCCESS;
}
static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
safi_t safi, bool use_json)
{
struct listnode *node, *nnode;
struct bgp *bgp;
char *vrf_name = NULL;
json_object *json = NULL;
json_object *json_vrf = NULL;
json_object *json_vrfs = NULL;
if (use_json) {
json = json_object_new_object();
json_vrfs = json_object_new_object();
}
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
vrf_name = bgp->name;
if (use_json) {
json_vrf = json_object_new_object();
} else {
vty_out(vty, "\nInstance %s:\n",
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
? VRF_DEFAULT_NAME : bgp->name);
}
bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf);
if (use_json) {
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
json_object_object_add(json_vrfs,
VRF_DEFAULT_NAME, json_vrf);
else
json_object_object_add(json_vrfs, vrf_name,
json_vrf);
}
}
if (use_json) {
json_object_object_add(json, "vrfs", json_vrfs);
vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
/* "show [ip] bgp route-leak" command. */
DEFUN (show_ip_bgp_route_leak,
show_ip_bgp_route_leak_cmd,
@ -11441,6 +11533,7 @@ DEFUN (show_ip_bgp_route_leak,
bool uj = use_json(argc, argv);
int idx = 0;
json_object *json = NULL;
/* show [ip] bgp */
if (argv_find(argv, argc, "ip", &idx)) {
@ -11470,7 +11563,13 @@ DEFUN (show_ip_bgp_route_leak,
return CMD_WARNING;
}
return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj);
if (vrf && strmatch(vrf, "all"))
return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj);
if (uj)
json = json_object_new_object();
return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json);
}
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,

View File

@ -1819,23 +1819,42 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
return CMD_SUCCESS;
}
/* Update redistribute vrf bitmap during triggers like
restart networking or delete/add VRFs */
void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
void bgp_redistribute_redo(struct bgp *bgp)
{
afi_t afi;
int i;
struct list *red_list;
struct listnode *node;
struct bgp_redist *red;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
red_list = bgp->redist[afi][i];
if (!red_list)
continue;
for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
bgp_redistribute_resend(bgp, afi, i,
red->instance);
}
}
}
}
/* Unset redistribute vrf bitmap during triggers like
restart networking or delete VRFs */
void bgp_unset_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
{
int i;
afi_t afi;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if ((old_vrf_id == VRF_UNKNOWN)
|| vrf_bitmap_check(zclient->redist[afi][i],
old_vrf_id)) {
if (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],
bgp->vrf_id);
}
return;
}

View File

@ -49,6 +49,7 @@ extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer);
extern void bgp_zebra_instance_register(struct bgp *);
extern void bgp_zebra_instance_deregister(struct bgp *);
extern void bgp_redistribute_redo(struct bgp *bgp);
extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t,
unsigned short);
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,

View File

@ -707,6 +707,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
{
struct peer_af *af;
int afid;
struct bgp *bgp;
if (!peer)
return NULL;
@ -715,6 +716,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
if (afid >= BGP_AF_MAX)
return NULL;
bgp = peer->bgp;
assert(peer->peer_af_array[afid] == NULL);
/* Allocate new peer af */
@ -725,6 +727,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
af->safi = safi;
af->afid = afid;
af->peer = peer;
bgp->af_peer_count[afi][safi]++;
return af;
}
@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
{
struct peer_af *af;
int afid;
struct bgp *bgp;
if (!peer)
return -1;
@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
if (!af)
return -1;
bgp = peer->bgp;
bgp_stop_announce_route_timer(af);
if (PAF_SUBGRP(af)) {
@ -768,8 +773,12 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
af->subgroup->id, peer->host);
}
update_subgroup_remove_peer(af->subgroup, af);
if (bgp->af_peer_count[afi][safi])
bgp->af_peer_count[afi][safi]--;
peer->peer_af_array[afid] = NULL;
XFREE(MTYPE_BGP_PEER_AF, af);
return 0;
@ -2714,7 +2723,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
peer->sort = group->conf->sort;
}
if (!group->conf->as) {
if (!group->conf->as && peer_sort(peer)) {
if (peer_sort(group->conf) != BGP_PEER_INTERNAL
&& peer_sort(group->conf) != peer_sort(peer)) {
if (as)

View File

@ -99,6 +99,9 @@ enum bgp_af_index {
for (afi = AFI_IP; afi < AFI_MAX; afi++) \
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
#define FOREACH_SAFI(safi) \
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
extern struct frr_pthread *bgp_pth_io;
extern struct frr_pthread *bgp_pth_ka;
@ -377,6 +380,9 @@ struct bgp {
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7)
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8)
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
/* Route table for next-hop lookup cache. */
struct bgp_table *nexthop_cache_table[AFI_MAX];
@ -1906,7 +1912,7 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf)
bgp->vrf_id = VRF_UNKNOWN;
}
extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
/* For benefit of rfapi */
extern struct peer *peer_new(struct bgp *bgp);

View File

@ -765,7 +765,7 @@ AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for con
enable_logfile_mask=${enable_logfile_mask:-0600}
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
MPATH_NUM=1
MPATH_NUM=16
case "${enable_multipath}" in
0)

View File

@ -1,9 +1,10 @@
.. _building-centos6:
CentOS 6
========================================
(As an alternative to this installation, you may prefer to create a FRR
rpm package yourself and install that package instead. See instructions
in redhat/README.rpm\_build.md on how to build a rpm package)
This document describes installation from source. If you want to build an RPM,
see :ref:`packaging-redhat`.
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
@ -24,7 +25,7 @@ CentOS 6 restrictions:
PIMd is needed
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
or higher (LDP can be built, but may have limited use without MPLS)
- Zebra is unable to detect what bridge/vrf an interface is associcated
- Zebra is unable to detect what bridge/vrf an interface is associated
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
you can use a newer kernel + headers to get this functionality)
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
@ -235,7 +236,7 @@ settings)::
# Controls source route verification
net.ipv4.conf.default.rp_filter = 0
Load the modifed sysctl's on the system:
Load the modified sysctl's on the system:
.. code-block:: shell

View File

@ -1,9 +1,8 @@
CentOS 7
========================================
(As an alternative to this installation, you may prefer to create a FRR
rpm package yourself and install that package instead. See instructions
in redhat/README.rpm\_build.md on how to build a rpm package)
This document describes installation from source. If you want to build an RPM,
see :ref:`packaging-redhat`.
CentOS 7 restrictions:
----------------------
@ -127,7 +126,7 @@ following content:
net.ipv4.conf.all.forwarding=1
net.ipv6.conf.all.forwarding=1
Load the modifed sysctl's on the system:
Load the modified sysctl's on the system:
::

View File

@ -0,0 +1,122 @@
Fedora 24+
==========
This document describes installation from source. If you want to build an RPM,
see :ref:`packaging-redhat`.
These instructions have been tested on Fedora 24+.
Installing Dependencies
-----------------------
.. code-block:: console
sudo dnf install git autoconf automake libtool make gawk \
readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \
pam-devel pytest bison flex c-ares-devel python3-devel python2-sphinx \
perl-core patch
.. include:: building-libyang.rst
Building & Installing FRR
-------------------------
Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
sudo groupadd -g 92 frr
sudo groupadd -r -g 85 frrvty
sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
-c "FRR FRRouting suite" -d /var/run/frr frr
Compile
^^^^^^^
.. include:: include-compile.rst
Install FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
sudo install -m 775 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
Tweak sysctls
^^^^^^^^^^^^^
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
MPLS (if supported by your platform). If your platform does not support MPLS,
skip the MPLS related configuration in this section.
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following
content:
::
#
# Enable packet forwarding
#
net.ipv4.conf.all.forwarding=1
net.ipv6.conf.all.forwarding=1
#
# Enable MPLS Label processing on all interfaces
#
#net.mpls.conf.eth0.input=1
#net.mpls.conf.eth1.input=1
#net.mpls.conf.eth2.input=1
#net.mpls.platform_labels=100000
.. note::
MPLS must be invidividually enabled on each interface that requires it. See
the example in the config block above.
Load the modifed sysctls on the system:
.. code-block:: console
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content:
::
# Load MPLS Kernel Modules
mpls-router
mpls-iptunnel
And load the kernel modules on the running system:
.. code-block:: console
sudo modprobe mpls-router mpls-iptunnel
Install service files
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
sudo systemctl enable frr
Enable daemons
^^^^^^^^^^^^^^
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
as required by changing the value to ``yes``.
Start FRR
^^^^^^^^^
.. code-block:: frr
sudo systemctl start frr

View File

@ -1,170 +0,0 @@
Fedora 24
=========================================
(As an alternative to this installation, you may prefer to create a FRR
rpm package yourself and install that package instead. See instructions
in redhat/README.rpm\_build.md on how to build a rpm package)
Install required packages
-------------------------
Add packages:
::
sudo dnf install git autoconf automake libtool make gawk \
readline-devel texinfo net-snmp-devel groff pkgconfig \
json-c-devel pam-devel pytest bison flex c-ares-devel \
python3-devel python3-sphinx
.. include:: building-libyang.rst
Get FRR, compile it and install it (from Git)
---------------------------------------------
**This assumes you want to build and install FRR from source and not
using any packages**
Add frr groups and user
^^^^^^^^^^^^^^^^^^^^^^^
::
sudo groupadd -g 92 frr
sudo groupadd -r -g 85 frrvty
sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
-c "FRR FRRouting suite" -d /var/run/frr frr
Download Source, configure and compile it
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(You may prefer different options on configure statement. These are just
an example.)
::
git clone https://github.com/frrouting/frr.git frr
cd frr
./bootstrap.sh
./configure \
--bindir=/usr/bin \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
--libdir=/usr/lib/frr \
--libexecdir=/usr/lib/frr \
--localstatedir=/var/run/frr \
--with-moduledir=/usr/lib/frr/modules \
--enable-snmp=agentx \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
--disable-exampledir \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make
make check
sudo make install
Create empty FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
sudo mkdir /var/log/frr
sudo mkdir /etc/frr
sudo touch /etc/frr/zebra.conf
sudo touch /etc/frr/bgpd.conf
sudo touch /etc/frr/ospfd.conf
sudo touch /etc/frr/ospf6d.conf
sudo touch /etc/frr/isisd.conf
sudo touch /etc/frr/ripd.conf
sudo touch /etc/frr/ripngd.conf
sudo touch /etc/frr/pimd.conf
sudo touch /etc/frr/ldpd.conf
sudo touch /etc/frr/nhrpd.conf
sudo touch /etc/frr/eigrpd.conf
sudo touch /etc/frr/babeld.conf
sudo chown -R frr:frr /etc/frr/
sudo touch /etc/frr/vtysh.conf
sudo chown frr:frrvty /etc/frr/vtysh.conf
sudo chmod 640 /etc/frr/*.conf
Install daemon config file
^^^^^^^^^^^^^^^^^^^^^^^^^^
::
sudo install -p -m 644 redhat/daemons /etc/frr/
sudo chown frr:frr /etc/frr/daemons
Edit /etc/frr/daemons as needed to select the required daemons
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
Enable the daemons as required by changing the value to ``yes``
Enable IP & IPv6 forwarding (and MPLS)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
following content: (Please make sure to list all interfaces with
required MPLS similar to ``net.mpls.conf.eth0.input=1``)
::
# Sysctl for routing
#
# Routing: We need to forward packets
net.ipv4.conf.all.forwarding=1
net.ipv6.conf.all.forwarding=1
#
# Enable MPLS Label processing on all interfaces
net.mpls.conf.eth0.input=1
net.mpls.conf.eth1.input=1
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
Load the modifed sysctl's on the system:
::
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
Create a new file ``/etc/modules-load.d/mpls.conf`` with the following
content:
::
# Load MPLS Kernel Modules
mpls-router
mpls-iptunnel
And load the kernel modules on the running system:
::
sudo modprobe mpls-router mpls-iptunnel
Install frr Service and redhat init files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
Enable required frr at startup
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
sudo systemctl enable frr
Reboot or start FRR manually
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
sudo systemctl start frr

View File

@ -11,7 +11,7 @@ FreeBSD 10 restrictions:
Install required packages
-------------------------
Add packages: (Allow the install of the package managment tool if this
Add packages: (Allow the install of the package management tool if this
is first package install and asked)
::

View File

@ -11,7 +11,7 @@ FreeBSD 11 restrictions:
Install required packages
-------------------------
Add packages: (Allow the install of the package managment tool if this
Add packages: (Allow the install of the package management tool if this
is first package install and asked)
.. code-block:: shell

View File

@ -11,7 +11,7 @@ FreeBSD 9 restrictions:
Install required packages
-------------------------
Add packages: (Allow the install of the package managment tool if this
Add packages: (Allow the install of the package management tool if this
is first package install and asked)
::

View File

@ -63,10 +63,10 @@ Usage
-----
Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
``DAEMONS=`` or don't install unneded packages For example: zebra bgpd ldpd
``DAEMONS=`` or don't install unneeded packages For example: zebra bgpd ldpd
isisd nhrpd ospfd ospf6d pimd ripd ripngd
Enable the serivce
Enable the service
^^^^^^^^^^^^^^^^^^
- ``service frr enable``

View File

@ -1,35 +1,30 @@
Ubuntu 14.04LTS
===============================================
Ubuntu 14.04 LTS
================
- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
limited use without MPLS) For an updated Ubuntu Kernel, see
http://kernel.ubuntu.com/~kernel-ppa/mainline/
This document describes installation from source. If you want to build a
``deb``, see :ref:`packaging-debian`.
Install required packages
-------------------------
Installing Dependencies
-----------------------
Add packages:
::
.. code-block:: console
apt-get update
apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo \
dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev python3-sphinx install-info build-essential
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev python3-sphinx install-info build-essential \
libsnmp-dev perl
.. include:: building-libyang.rst
Get FRR, compile it and install it (from Git)
---------------------------------------------
Building & Installing FRR
-------------------------
**This assumes you want to build and install FRR from source and not
using any packages**
Add frr groups and user
Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
::
.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
@ -37,102 +32,104 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
Download Source, configure and compile it
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compile
^^^^^^^
(You may prefer different options on configure statement. These are just
an example.)
.. include:: include-compile.rst
Install FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
sudo install -m 775 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
Tweak sysctls
^^^^^^^^^^^^^
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
MPLS (if supported by your platform). If your platform does not support MPLS,
skip the MPLS related configuration in this section.
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
other settings):
::
git clone https://github.com/frrouting/frr.git frr
cd frr
./bootstrap.sh
./configure \
--prefix=/usr \
--enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make
make check
sudo make install
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
Create empty FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
Reboot or use ``sysctl -p`` to apply the same config to the running system.
Add MPLS kernel modules
"""""""""""""""""""""""
.. warning::
MPLS is not supported on Ubuntu 14.04 with the default kernel. MPLS requires
kernel 4.5 or higher. LDPD can be built, but may have limited use without
MPLS. For an updated Ubuntu Kernel, see
http://kernel.ubuntu.com/~kernel-ppa/mainline/
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
::
sudo install -m 755 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
# Load MPLS Kernel Modules
mpls_router
mpls_iptunnel
Enable IP & IPv6 forwarding
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
other settings)
And load the kernel modules on the running system:
.. code-block:: console
sudo modprobe mpls-router mpls-iptunnel
Enable MPLS Forwarding
""""""""""""""""""""""
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
::
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
**Reboot** or use ``sysctl -p`` to apply the same config to the running
system
# Enable MPLS Label processing on all interfaces
net.mpls.conf.eth0.input=1
net.mpls.conf.eth1.input=1
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
Install the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^^^
::
.. code-block:: console
sudo install -m 755 tools/frr /etc/init.d/frr
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 755 tools/frr /etc/init.d/frr
Enable daemons
^^^^^^^^^^^^^^
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
those daemons you want to start by systemd.
| For example.
::
zebra=yes
bgpd=yes
ospfd=yes
ospf6d=yes
ripd=yes
ripngd=yes
isisd=yes
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
as required by changing the value to ``yes``.
Start the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^
- /etc/init.d/frr start
- use ``/etc/init.d/frr status`` to check its status.
.. code-block:: console
/etc/init.d/frr start
Use ``/etc/init.d/frr status`` to check its status.

View File

@ -1,172 +1,134 @@
Ubuntu 16.04LTS
===============================================
Ubuntu 16.04 LTS
================
- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
limited use without MPLS) For an updated Ubuntu Kernel, see
http://kernel.ubuntu.com/~kernel-ppa/mainline/
This document describes installation from source. If you want to build a
``deb``, see :ref:`packaging-debian`.
Install required packages
-------------------------
Installing Dependencies
-----------------------
Add packages:
::
.. code-block:: console
apt-get update
apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \
git autoconf automake libtool make gawk libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
python3-sphinx install-info build-essential libsystemd-dev
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst
Get FRR, compile it and install it (from Git)
---------------------------------------------
Building & Installing FRR
-------------------------
**This assumes you want to build and install FRR from source and not
using any packages**
Add frr groups and user
Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
::
.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
sudo adduser --system --ingroup frr --home /var/run/frr/ \
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
sudo adduser --system --ingroup frr --home /var/run/frr/ \
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
Download Source, configure and compile it
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compile
^^^^^^^
(You may prefer different options on configure statement. These are just
an example.)
.. include:: include-compile.rst
Install FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
sudo install -m 775 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
Tweak sysctls
^^^^^^^^^^^^^
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
MPLS (if supported by your platform). If your platform does not support MPLS,
skip the MPLS related configuration in this section.
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
other settings):
::
git clone https://github.com/frrouting/frr.git frr
cd frr
./bootstrap.sh
./configure \
--prefix=/usr \
--enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-fpm \
--enable-systemd=yes \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make
make check
sudo make install
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
Create empty FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
::
sudo install -m 755 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
Enable IPv4 & IPv6 forwarding
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
other settings)
::
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
Enable MPLS Forwarding (with Linux Kernel >= 4.5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
line equal to ``net.mpls.conf.eth0.input`` or each interface used with
MPLS
::
# Enable MPLS Label processing on all interfaces
net.mpls.conf.eth0.input=1
net.mpls.conf.eth1.input=1
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
Reboot or use ``sysctl -p`` to apply the same config to the running system.
Add MPLS kernel modules
^^^^^^^^^^^^^^^^^^^^^^^
"""""""""""""""""""""""
Add the following lines to ``/etc/modules-load.d/modules.conf``:
.. warning::
MPLS is not supported on Ubuntu 16.04 with the default kernel. MPLS requires
kernel 4.5 or higher. LDPD can be built, but may have limited use without
MPLS. For an updated Ubuntu Kernel, see
http://kernel.ubuntu.com/~kernel-ppa/mainline/
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
::
# Load MPLS Kernel Modules
mpls-router
mpls-iptunnel
# Load MPLS Kernel Modules
mpls_router
mpls_iptunnel
**Reboot** or use ``sysctl -p`` to apply the same config to the running
system
Install the systemd service (if rebooted from last step, change directory back to frr directory)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
And load the kernel modules on the running system:
.. code-block:: console
sudo modprobe mpls-router mpls-iptunnel
Enable MPLS Forwarding
""""""""""""""""""""""
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
::
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
# Enable MPLS Label processing on all interfaces
net.mpls.conf.eth0.input=1
net.mpls.conf.eth1.input=1
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
Install service files
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
sudo systemctl enable frr
Enable daemons
^^^^^^^^^^^^^^
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
those daemons you want to start by systemd.
| For example.
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
as required by changing the value to ``yes``.
::
Start FRR
^^^^^^^^^
zebra=yes
bgpd=yes
ospfd=yes
ospf6d=yes
ripd=yes
ripngd=yes
isisd=yes
.. code-block:: console
Enable the systemd service
^^^^^^^^^^^^^^^^^^^^^^^^^^
- systemctl enable frr
Start the systemd service
^^^^^^^^^^^^^^^^^^^^^^^^^
- systemctl start frr
- use ``systemctl status frr`` to check its status.
systemctl start frr

View File

@ -1,55 +1,44 @@
Ubuntu 18.04 LTS
================
Install dependencies
--------------------
This document describes installation from source. If you want to build a
``deb``, see :ref:`packaging-debian`.
Required packages
^^^^^^^^^^^^^^^^^
Installing Dependencies
-----------------------
::
.. code-block:: console
sudo apt update
sudo apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
python3-sphinx install-info build-essential libsystemd-dev
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst
Optional packages
^^^^^^^^^^^^^^^^^
Dependencies for additional functionality can be installed as-desired.
Protobuf
~~~~~~~~
^^^^^^^^
::
.. code-block:: console
sudo apt-get install \
protobuf-c-compiler \
libprotobuf-c-dev
sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
ZeroMQ
~~~~~~
^^^^^^
::
.. code-block:: console
sudo apt-get install \
libzmq5 \
libzmq3-dev
sudo apt-get install libzmq5 libzmq3-dev
Get FRR, compile it and install it (from Git)
---------------------------------------------
Building & Installing FRR
-------------------------
**This assumes you want to build and install FRR from source and not
using any packages**
Add frr groups and user
Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
::
.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
@ -57,104 +46,29 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
Download source
^^^^^^^^^^^^^^^
::
git clone https://github.com/frrouting/frr.git frr
Configure
^^^^^^^^^
Options below are provided as an example.
.. seealso:: *Installation* section of user guide
.. code-block:: shell
cd frr
./bootstrap.sh
./configure \
--prefix=/usr \
--enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-fpm \
--enable-systemd=yes \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
If optional packages were installed, the associated feature may now be
enabled.
.. option:: --enable-protobuf
Enable support for protobuf transport
.. option:: --enable-zeromq
Enable support for ZeroMQ transport
Compile
^^^^^^^
::
.. include:: include-compile.rst
make
make check
sudo make install
Install FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Create empty FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: console
Although not strictly necessary, it's good practice to create empty
configuration files _before_ starting FRR. This assures that the permissions
are correct. If the files are not already present, FRR will create them.
It's also important to consider _which_ files to create. FRR supports writing
configuration to a monolithic file, :file:`/etc/frr/frr.conf`.
.. seealso:: *VTYSH* section of user guide
The presence of :file:`/etc/frr/frr.conf` on startup implicitly configures FRR
to ignore daemon-specific configuration files.
Daemon-specific configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
sudo install -m 755 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
Monolithic configuration
~~~~~~~~~~~~~~~~~~~~~~~~
Tweak sysctls
^^^^^^^^^^^^^
::
sudo install -m 755 -o frr -g frr -d /var/log/frr
sudo install -m 775 -o frr -g frrvty -d /etc/frr
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf
Enable IPv4 & IPv6 forwarding
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
MPLS (if supported by your platform). If your platform does not support MPLS,
skip the MPLS related configuration in this section.
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
other settings):
@ -169,8 +83,10 @@ other settings):
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
Reboot or use ``sysctl -p`` to apply the same config to the running system.
Add MPLS kernel modules
^^^^^^^^^^^^^^^^^^^^^^^
"""""""""""""""""""""""
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
@ -181,10 +97,15 @@ enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
mpls_router
mpls_iptunnel
Reboot or use ``sysctl -p`` to apply the same config to the running system.
And load the kernel modules on the running system:
.. code-block:: console
sudo modprobe mpls-router mpls-iptunnel
Enable MPLS Forwarding
^^^^^^^^^^^^^^^^^^^^^^
""""""""""""""""""""""
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
@ -197,48 +118,24 @@ equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
Install the systemd service
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Install service files
^^^^^^^^^^^^^^^^^^^^^
::
.. code-block:: console
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo systemctl enable frr
Enable daemons
^^^^^^^^^^^^^^
Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those
daemons you want to start by systemd. For example:
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
as required by changing the value to ``yes``.
::
zebra=yes
bgpd=yes
ospfd=yes
ospf6d=yes
ripd=yes
ripngd=yes
isisd=yes
Enable the systemd service
^^^^^^^^^^^^^^^^^^^^^^^^^^
Enabling the systemd service causes FRR to be started upon boot. To enable it,
use the following command:
.. code-block:: shell
systemctl enable frr
Start the systemd service
^^^^^^^^^^^^^^^^^^^^^^^^^
Start FRR
^^^^^^^^^
.. code-block:: shell
systemctl start frr
After starting the service, you can use ``systemctl status frr`` to check its
status.

View File

@ -1,57 +1,55 @@
The libyang library can be installed from third-party packages available `here
<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF
support. Unfortunately, most distributions do not yet offer a ``libyang``
package from their repositories. Therefore we offer two options to install this
library.
Note: the libyang dev/devel packages need to be installed in addition
to the libyang core package in order to build FRR successfully.
**Option 1: Binary Install**
The FRR project builds binary ``libyang`` packages, which we offer for download
`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
.. warning::
libyang ABI version 0.16.74 or newer will be required to build FRR in the
near future since it significantly eases build and installation
considerations. "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2"
is equal to 0.16.52 and will stop working. The CI artifacts will be
updated shortly.
For example, for CentOS 7.x:
.. code-block:: shell
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-0.16.46-0.x86_64.rpm
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-devel-0.16.46-0.x86_64.rpm
sudo rpm -i libyang-0.16.46-0.x86_64.rpm libyang-devel-0.16.46-0.x86_64.rpm
or Ubuntu 18.04:
.. code-block:: shell
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb
sudo apt install libpcre3-dev
sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb
``libyang`` version 0.16.74 or newer is required to build FRR.
.. note::
For Debian-based systems, the official libyang package requires recent
versions of swig (3.0.12) and debhelper (11) which are only available in
Debian buster (10). However, libyang packages built on Debian buster can
be installed on both Debian jessie (8) and Debian stretch (9), as well as
various Ubuntu systems. The python3-yang package will not work, but the
other packages (libyang-dev is the one needed for FRR) will.
Alternatively, libyang can be built and installed manually by following
the steps below:
The ``libyang`` development packages need to be installed in addition to the
libyang core package in order to build FRR successfully. Make sure to
download and install those from the link above alongside the binary
packages.
.. code-block:: shell
Depending on your platform, you may also need to install the PCRE
development package. Typically this is ``libpcre-dev`` or ``pcre-devel``.
git clone https://github.com/opensourcerouting/libyang
.. note::
For Debian-based systems, the official ``libyang`` package requires recent
versions of ``swig`` (3.0.12) and ``debhelper`` (11) which are only
available in Debian buster (10). However, ``libyang`` packages built on
Debian buster can be installed on both Debian jessie (8) and Debian stretch
(9), as well as various Ubuntu systems. The ``python3-yang`` package will
not work, but the other packages (``libyang-dev`` is the one needed for FRR)
will.
**Option 2: Source Install**
.. note::
Ensure that the `libyang build requirements
<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
are met before continuing. Usually this entails installing ``cmake`` and
``libpcre-dev`` or ``pcre-devel``.
.. code-block:: console
git clone https://github.com/CESNET/libyang.git
cd libyang
git checkout -b tmp origin/tmp
mkdir build; cd build
cmake -DENABLE_LYD_PRIV=ON ..
cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
make
sudo make install
When building libyang on CentOS 6, it's also necessary to pass the
``-DENABLE_CACHE=OFF`` parameter to cmake.
Note: please check the `libyang build requirements
<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
first.

View File

@ -12,7 +12,7 @@ Building FRR
building-frr-for-centos7
building-frr-for-debian8
building-frr-for-debian9
building-frr-for-fedora24
building-frr-for-fedora
building-frr-for-freebsd10
building-frr-for-freebsd11
building-frr-for-freebsd9

View File

@ -131,7 +131,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst']
exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst', 'include-compile.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.

View File

@ -6,7 +6,7 @@ Hooks
Libfrr provides type-safe subscribable hook points where other pieces of
code can add one or more callback functions. "type-safe" in this case
applies to the function pointers used for subscriptions. The
implementations checks (at compile-time) wheter a callback to be added has
implementations checks (at compile-time) whether a callback to be added has
the appropriate function signature (parameters) for the hook.
Example:

View File

@ -0,0 +1,37 @@
Clone the FRR git repo and use the included ``configure`` script to configure
FRR's build time options to your liking. The full option listing can be
obtained by running ``./configure -h``. The options shown below are examples.
.. note::
If your platform uses ``systemd``, please make sure to add
``--enable-systemd=yes`` to your configure options.
.. code-block:: console
git clone https://github.com/frrouting/frr.git frr
cd frr
./bootstrap.sh
./configure \
--prefix=/usr \
--includedir=\${prefix}/include \
--enable-exampledir=\${prefix}/share/doc/frr/examples \
--bindir=\${prefix}/bin \
--sbindir=\${prefix}/lib/frr \
--libdir=\${prefix}/lib/frr \
--libexecdir=\${prefix}/lib/frr \
--localstatedir=/var/run/frr \
--sysconfdir=/etc/frr \
--with-moduledir=\${prefix}/lib/frr/modules \
--with-libyang-pluginsdir=\${prefix}/lib/frr/libyang_plugins \
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-snmp=agentx \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
make
sudo make install

View File

@ -18,7 +18,7 @@ maybe by a syslog collector from all routers.) Therefore, anything that
needs to get the user in the loop—and only these things—are warnings or
errors.
Note that this doesn't neccessarily mean the user needs to fix something in
Note that this doesn't necessarily mean the user needs to fix something in
the FRR instance. It also includes when we detect something else needs
fixing, for example another router, the system we're running on, or the
configuration. The common point is that the user should probably do

View File

@ -3,7 +3,7 @@
Memtypes
========
FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
FRR includes wrappers around ``malloc()`` and ``free()`` that count the number
of objects currently allocated, for each of a defined ``MTYPE``.
To this extent, there are *memory groups* and *memory types*. Each memory

View File

@ -284,7 +284,7 @@ Each message begins with the following header:
The message type field can take one of the following values:
+-------------------------------+---------+
| Messages to OSPF deamon | Value |
| Messages to OSPF daemon | Value |
+===============================+=========+
| MSG\_REGISTER\_OPAQUETYPE | 1 |
+-------------------------------+---------+
@ -300,7 +300,7 @@ The message type field can take one of the following values:
+-------------------------------+---------+
+-----------------------------+---------+
| Messages from OSPF deamon | Value |
| Messages from OSPF daemon | Value |
+=============================+=========+
| MSG\_REPLY | 10 |
+-----------------------------+---------+

View File

@ -31,7 +31,7 @@ Implementation details
Concepts
^^^^^^^^
Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various
Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various
information:
* **Router Information:** flood the Segment Routing capabilities of the node.
@ -40,7 +40,7 @@ information:
* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
* **Extended Prefix:** flood the Prefix Segment Identifier
The implementation follow previous TE and Router Information codes. It used the
The implementation follows previous TE and Router Information codes. It used the
OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This
latter is mandatory for the implementation as it provides the Callback to
Segment Routing functions (see below) when an Extended Link / Prefix or Router
@ -71,7 +71,7 @@ The figure below shows the relation between the various files:
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
respectively ospf_ext.c.
* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB
Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB
and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs.
* ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque
LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
@ -129,8 +129,8 @@ Opaque LSA it is the `ospf_opaque_lsa_install_hook()`. For deletion, it is
Note that incoming LSA which is already present in the LSDB will be inserted
after the old instance of this LSA remove from the LSDB. Thus, after the first
time, each incoming LSA will trigger a `delete` following by an `install`. This
is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done
by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage
is not very helpful to handle real LSA deletion. In fact, LSA deletion is done
by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage
function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So,
to handle LSA Flush, the best is to look to the LSA age to determine if it is
an installation or a future deletion i.e. the flushed LSA is first store in the
@ -144,7 +144,7 @@ introduced. When this command is activated, function
`ospf_router_info_update_sr()` is called to indicate to Router Information
process that Segment Routing TLVs must be flood. Same function is called to
modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD)
TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity
TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility
to modify this TLV is offer by the code.
When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
@ -159,8 +159,8 @@ Extended Link Prefix LSAs
^^^^^^^^^^^^^^^^^^^^^^^^^
Like for Router Information, Segment Routing is activate at the Extended
Link/Prefix level with new `segment-routing on` command. This trigger
automtically the flooding of Extended Link LSA for all ospf interface where
Link/Prefix level with new `segment-routing on` command. This triggers
automatically the flooding of Extended Link LSA for all ospf interfaces where
adjacency is full. For Extended Prefix LSA, the new CLI command
`segment-routing prefix ...` will trigger the flooding of Prefix SID
TLV/SubTLVs.
@ -255,7 +255,7 @@ The first segment-routing statement enable it. The Second one set the SRGB,
third line the MSD and finally, set the Prefix SID index for a given prefix.
Note that only prefix of Loopback interface could be configured with a Prefix
SID. It is possible to add `no-php-flag` at the end of the prefix command to
disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop
disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
the MPLS label prior to sending the packet.
Known limitations

View File

@ -1,3 +1,5 @@
.. _packaging-debian:
Packaging Debian
================

View File

@ -0,0 +1,85 @@
.. _packaging-redhat:
Packaging Red Hat
=================
Tested on CentOS 6, CentOS 7 and Fedora 24.
1. On CentOS 6, refer to :ref:`building-centos6` for details on installing
sufficiently up-to-date package versions to enable building FRR.
Newer automake/autoconf/bison is only needed to build the RPM and is **not**
needed to install the binary RPM package.
2. Install the build dependencies for your platform. Refer to the
platform-specific build documentation on how to do this.
3. Install the following additional packages::
yum install rpm-build net-snmp-devel pam-devel libcap-devel
If your platform uses systemd::
yum install systemd-devel
If ``yum`` is not present on your system, use ``dnf`` instead.
3. Checkout FRR::
git clone https://github.com/frrouting/frr.git frr
4. Run Bootstrap and make distribution tar.gz::
cd frr
./bootstrap.sh
./configure --with-pkg-extra-version=-MyRPMVersion SPHINXBUILD=sphinx-build2.7
make dist
.. note::
The only ``configure`` option respected when building RPMs is
``--with-pkg-extra-version``.
5. Create RPM directory structure and populate with sources::
mkdir rpmbuild
mkdir rpmbuild/SOURCES
mkdir rpmbuild/SPECS
cp redhat/*.spec rpmbuild/SPECS/
cp frr*.tar.gz rpmbuild/SOURCES/
6. Edit :file:`rpm/SPECS/frr.spec` with configuration as needed.
Look at the beginning of the file and adjust the following parameters to
enable or disable features as required::
############### FRRouting (FRR) configure options #################
# with-feature options
%{!?with_pam: %global with_pam 0 }
%{!?with_ospfclient: %global with_ospfclient 1 }
%{!?with_ospfapi: %global with_ospfapi 1 }
%{!?with_irdp: %global with_irdp 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_ldpd: %global with_ldpd 1 }
%{!?with_nhrpd: %global with_nhrpd 1 }
%{!?with_eigrp: %global with_eigrpd 1 }
%{!?with_shared: %global with_shared 1 }
%{!?with_multipath: %global with_multipath 256 }
%{!?frr_user: %global frr_user frr }
%{!?vty_group: %global vty_group frrvty }
%{!?with_fpm: %global with_fpm 0 }
%{!?with_watchfrr: %global with_watchfrr 1 }
%{!?with_bgp_vnc: %global with_bgp_vnc 0 }
%{!?with_pimd: %global with_pimd 1 }
%{!?with_rpki: %global with_rpki 0 }
7. Build the RPM::
rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec
If building with RPKI, then download and install the additional RPKI
packages from
https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
If all works correctly, then you should end up with the RPMs under
:file:`rpmbuild/RPMS` and the source RPM under :file:`rpmbuild/SRPMS`.

View File

@ -7,3 +7,4 @@ Packaging
maintainer-release-build
packaging-debian
packaging-redhat

View File

@ -5,13 +5,12 @@
dev_RSTFILES = \
doc/developer/bgp-typecodes.rst \
doc/developer/bgpd.rst \
doc/developer/building-frr-for-openwrt.rst \
doc/developer/building-frr-for-alpine.rst \
doc/developer/building-frr-for-centos6.rst \
doc/developer/building-frr-for-centos7.rst \
doc/developer/building-frr-for-debian8.rst \
doc/developer/building-frr-for-debian9.rst \
doc/developer/building-frr-for-fedora24.rst \
doc/developer/building-frr-for-fedora.rst \
doc/developer/building-frr-for-freebsd10.rst \
doc/developer/building-frr-for-freebsd11.rst \
doc/developer/building-frr-for-freebsd9.rst \
@ -19,6 +18,7 @@ dev_RSTFILES = \
doc/developer/building-frr-for-netbsd7.rst \
doc/developer/building-frr-for-omnios.rst \
doc/developer/building-frr-for-openbsd6.rst \
doc/developer/building-frr-for-openwrt.rst \
doc/developer/building-frr-for-ubuntu1404.rst \
doc/developer/building-frr-for-ubuntu1604.rst \
doc/developer/building-frr-for-ubuntu1804.rst \
@ -27,6 +27,7 @@ dev_RSTFILES = \
doc/developer/cli.rst \
doc/developer/conf.py \
doc/developer/hooks.rst \
doc/developer/include-compile.rst \
doc/developer/index.rst \
doc/developer/library.rst \
doc/developer/logging.rst \
@ -37,8 +38,9 @@ dev_RSTFILES = \
doc/developer/ospf-api.rst \
doc/developer/ospf-sr.rst \
doc/developer/ospf.rst \
doc/developer/packaging.rst \
doc/developer/packaging-debian.rst \
doc/developer/packaging-redhat.rst
doc/developer/packaging.rst \
doc/developer/testing.rst \
doc/developer/topotests-snippets.rst \
doc/developer/topotests.rst \

View File

@ -48,17 +48,17 @@ A sample of this snippet in a test can be found `here
Interacting with equipment
^^^^^^^^^^^^^^^^^^^^^^^^^^
You might want to interact with the topology equipments during the tests and
You might want to interact with the topology equipment during the tests and
there are different ways to do so.
Notes:
1. When using the Topogen API, all the equipments code derive from ``Topogear``
1. When using the Topogen API, all the equipment code derives from ``Topogear``
(`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by
yourself how the abstractions that will be mentioned here works.
yourself how the abstractions that will be mentioned here work.
2. When not using the ``Topogen`` API there is only one way to interact with
the equipments, which is by calling the ``mininet`` API functions directly
the equipment, which is by calling the ``mininet`` API functions directly
to spawn commands.
Interacting with the Linux sandbox
@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures:
.. note::
``vtysh_(multi)cmd`` is only available for router type of equipments.
``vtysh_(multi)cmd`` is only available for router types of equipment.
Invoking mininet CLI
^^^^^^^^^^^^^^^^^^^^
@ -195,7 +195,7 @@ Loading JSON from a file:
Comparing JSON output
^^^^^^^^^^^^^^^^^^^^^
After obtaining JSON output formated with Python data structures, you may use
After obtaining JSON output formatted with Python data structures, you may use
it to assert a minimalist schema:
.. code:: py

View File

@ -151,7 +151,7 @@ Collect Memory Leak Information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FRR processes have the capabilities to report remaining memory allocations upon
exit. To enable the reporting of the memory, define an enviroment variable
exit. To enable the reporting of the memory, define an environment variable
``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
@ -410,7 +410,7 @@ Defining the Topology
The first step to write a new test is to define the topology. This step can be
done in many ways, but the recommended is to use Graphviz to generate a drawing
of the topology. It allows us to see the topology graphically and to see the
names of equipments, links and addresses.
names of equipment, links and addresses.
Here is an example of Graphviz dot file that generates the template topology
:file:`tests/topotests/example-test/test_template.dot` (the inlined code might

View File

@ -43,7 +43,7 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`.
Command Extraction
------------------
When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR
When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR
codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
contains the name of the command plus ``_vtysh``, as well as a flag that
@ -167,7 +167,7 @@ Protocol
VTYSH communicates with FRR daemons by way of domain socket. Each daemon
creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The
protocol is very simple. In the VTYSH to daemon direction, messages are simply
NULL-terminated strings, whose content are CLI commands. Here is a typical
NUL-terminated strings, whose content are CLI commands. Here is a typical
message from VTYSH to a daemon:
::
@ -178,7 +178,7 @@ message from VTYSH to a daemon:
00000010: 6c0a 00 l..
The response format has some more data in it. First is a NULL-terminated string
The response format has some more data in it. First is a NUL-terminated string
containing the plaintext response, which is just the output of the command that
was sent in the request. This is displayed to the user. The plaintext response
is followed by 3 null marker bytes, followed by a 1-byte status code that

View File

@ -99,9 +99,14 @@ Bugfix releases are made as needed at 1 month intervals until the next
``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
bugfix releases may occur sooner.
Bugfixes are applied to the two most recent releases. Security fixes are
backported to all releases less than or equal to at least one year old. Security
fixes may also be backported to older releases depending on severity.
Bugfixes are applied to the two most recent releases. However, backporting of bug
fixes to older than the two most recent releases will not be prevented, if acked
under the classical development workflow applying for a pull request.
Security fixes are backported to all releases less than or equal to at least one
year old. Security fixes may also be backported to older releases depending on
severity.
Long term support branches ( LTS )
-----------------------------------------
@ -128,7 +133,7 @@ branch is required. The work can be shared by multiple people. In all cases, the
must be at least one person that is in charge of the maintenance branch. The person
on people responsible for a maintenance branch must be a FRR maintainer. Note that
they may choose to abandon support for the maintenance branch at any time. If
noone takes over the responsibility of the LTS branch, then the support will be
no one takes over the responsibility of the LTS branch, then the support will be
discontinued.
The LTS branch duties are the following ones:
@ -371,7 +376,7 @@ system in which submissions from an individual representing one company should
be merged by someone unaffiliated with that company.
Guidelines for code review
""""""""""""""""""""""""""
--------------------------
- As a rule of thumb, the depth of the review should be proportional to the
scope and / or impact of the patch.

View File

@ -129,7 +129,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst']
exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst', 'bfd-options.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.

View File

@ -1,3 +1,3 @@
.. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path]
.. |synopsis-options-hv| replace:: [-h] [-v]
.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8)
.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), mtracebis(8)

View File

@ -390,7 +390,7 @@ Terminal Mode Commands
.. index:: find COMMAND...
.. clicmd:: find COMMAND...
This commmand performs a simple substring search across all defined commands
This command performs a simple substring search across all defined commands
in all modes. As an example, suppose you're in enable mode and can't
remember where the command to turn OSPF segment routing on is:

View File

@ -511,8 +511,8 @@ cause may lead to routing instability or oscillation across multiple speakers
in iBGP topologies. This can occur with full-mesh iBGP, but is particularly
problematic in non-full-mesh iBGP topologies that further reduce the routing
information known to each speaker. This has primarily been documented with iBGP
route-reflection topologies. However, any route-hiding technologies potentially
could also exacerbate oscillation with MED.
:ref:`route-reflection <bgp-route-reflector>` topologies. However, any
route-hiding technologies potentially could also exacerbate oscillation with MED.
This second issue occurs where speakers each have only a subset of routes, and
there are cycles in the preferences between different combinations of routes -
@ -1145,7 +1145,7 @@ is 4 octet long. The following format is used to define the community value.
``graceful-shutdown`` represents well-known communities value
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
the purpose Graceful BGP Session Shutdown to reduce the amount of
lost traffic when taking BGP sessions down for maintainance. The use
lost traffic when taking BGP sessions down for maintenance. The use
of the community needs to be supported from your peers side to
actually have any effect.
@ -1176,20 +1176,20 @@ is 4 octet long. The following format is used to define the community value.
``llgr-stale``
``llgr-stale`` represents well-known communities value ``LLGR_STALE``
``0xFFFF0006`` ``65535:6``.
Assigned and intented only for use with routers supporting the
Assigned and intended only for use with routers supporting the
Long-lived Graceful Restart Capability as described in
[Draft-IETF-uttaro-idr-bgp-persistence]_.
Routers recieving routes with this community may (depending on
Routers receiving routes with this community may (depending on
implementation) choose allow to reject or modify routes on the
presence or absence of this community.
``no-llgr``
``no-llgr`` represents well-known communities value ``NO_LLGR``
``0xFFFF0007`` ``65535:7``.
Assigned and intented only for use with routers supporting the
Assigned and intended only for use with routers supporting the
Long-lived Graceful Restart Capability as described in
[Draft-IETF-uttaro-idr-bgp-persistence]_.
Routers recieving routes with this community may (depending on
Routers receiving routes with this community may (depending on
implementation) choose allow to reject or modify routes on the
presence or absence of this community.
@ -1251,7 +1251,7 @@ UPDATE messages.
There are two types of community list:
standard
This type accepts an explicit value for the atttribute.
This type accepts an explicit value for the attribute.
expanded
This type accepts a regular expression. Because the regex must be
@ -2240,10 +2240,15 @@ Displaying Routes by AS Path
Route Reflector
===============
.. note:: This documentation is woefully incomplete.
BGP routers connected inside the same AS through BGP belong to an internal
BGP session, or IBGP. In order to prevent routing table loops, IBGP does not
advertise IBGP-learned routes to other routers in the same session. As such,
IBGP requires a full mesh of all peers. For large networks, this quickly becomes
unscalable. Introducing route reflectors removes the need for the full-mesh.
.. index:: bgp cluster-id A.B.C.D
.. clicmd:: bgp cluster-id A.B.C.D
When route reflectors are configured, these will reflect the routes announced
by the peers configured as clients. A route reflector client is configured
with:
.. index:: neighbor PEER route-reflector-client
.. clicmd:: neighbor PEER route-reflector-client
@ -2251,6 +2256,13 @@ Route Reflector
.. index:: no neighbor PEER route-reflector-client
.. clicmd:: no neighbor PEER route-reflector-client
To avoid single points of failure, multiple route reflectors can be configured.
A cluster is a collection of route reflectors and their clients, and is used
by route reflectors to avoid looping.
.. index:: bgp cluster-id A.B.C.D
.. clicmd:: bgp cluster-id A.B.C.D
.. _routing-policy:
@ -2469,7 +2481,7 @@ certainly contains silly mistakes, if not serious flaws.
route-map rm-no-export permit 20
!
route-map rm-blackhole permit 10
description blackhole, up-pref and ensure it cant escape this AS
description blackhole, up-pref and ensure it cannot escape this AS
set ip next-hop 127.0.0.1
set local-preference 10
set community additive no-export

View File

@ -167,7 +167,7 @@ set. That VRF will then be selected. The below full configuration example
depicts how Route Targets are configured and how VRFs and cross VRF
configuration is done. Note that the VRF are mapped on Linux Network
Namespaces. For data traffic to cross VRF boundaries, virtual ethernet
interfaces are created with private IP adressing scheme.
interfaces are created with private IP addressing scheme.
.. code-block:: frr
@ -322,7 +322,7 @@ There are some other known issues:
- The validation procedure depicted in :rfc:`5575` is not available.
This validation procedure has not been implemented, as this feature was not
used in the existing setups you shared wih us.
used in the existing setups you shared with us.
- The filtering action shaper value, if positive, is not used to apply shaping.

View File

@ -272,10 +272,11 @@ options from the list below.
.. option:: --enable-multipath=X
Compile FRR with up to X way ECMP supported. This number can be from 0-999.
For backwards compatability with older configure options when setting X = 0,
For backwards compatibility with older configure options when setting X = 0,
we will build FRR with 64 way ECMP. This is needed because there are
hardcoded arrays that FRR builds towards, so we need to know how big to
make these arrays at build time.
make these arrays at build time. Additionally if this parameter is
not passed in FRR will default to 16 ECMP.
.. option:: --enable-shell-access

View File

@ -218,7 +218,7 @@ To start OSPF process you have to specify the OSPF router.
SPF-triggering event occurs within the hold-time of the previous SPF
calculation.
This command supercedes the *timers spf* command in previous FRR
This command supersedes the *timers spf* command in previous FRR
releases.
.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)

View File

@ -88,7 +88,7 @@ end destination.
When a incoming packet matches the destination prefix specified, take the
packet and forward according to the nexthops specified. This command accepts
both v4 and v6 prefixes. This command is used in conjuction of the
both v4 and v6 prefixes. This command is used in conjunction of the
:clicmd:`match src-ip PREFIX` command for matching.
.. clicmd:: set nexthop-group NAME

View File

@ -210,8 +210,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
Set the IGMP version used on this interface. The default value is 3.
.. index:: ip multicat boundary oil WORD
.. clicmd:: ip multicat boundary oil WORD
.. index:: ip multicast boundary oil WORD
.. clicmd:: ip multicast 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 denied by the

View File

@ -29,7 +29,7 @@ documented elsewhere.
Using SHARP
===========
All sharp commands are under the enable node and preceeded by the ``sharp``
All sharp commands are under the enable node and preceded by the ``sharp``
keyword. At present, no sharp commands will be preserved in the config.
.. index:: sharp install

View File

@ -380,7 +380,7 @@ At startup, FRR detects the presence of that file. It detects that the file
statistics information matches the same file statistics information as
`/proc/self/ns/net` ( through stat() function). As statistics information
matches, then `vrf0` stands for the new default namespace name.
Consequently, the VRF naming `Default` will be overriden by the new discovered
Consequently, the VRF naming `Default` will be overridden by the new discovered
namespace name `vrf0`.
For those who don't use VRF backend with *Linux network namespace*, it is
@ -422,7 +422,7 @@ in routing entry, and can be configured like a route:
.. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
.. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
NETWORK ans MASK stand for the IP prefix entry to be added as static
NETWORK and MASK stand for the IP prefix entry to be added as static
route entry.
GATEWAY is the gateway IP address to reach, in order to reach the prefix.
INTERFACE is the interface behind which the prefix is located.

View File

@ -1,35 +1,58 @@
FROM alpine:3.7 as source-builder
ARG commit
RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \
binutils binutils-libs bison bsd-compat-headers build-base \
c-ares c-ares-dev ca-certificates cryptsetup-libs curl \
device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \
git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \
libgomp libisoburn libisofs libltdl libressl libssh2 \
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \
patch pax-utils pcre perl pkgconf python2 python2-dev readline \
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \
groff gzip bc py-sphinx
ADD . /src
RUN (cd /src && \
./bootstrap.sh && \
./configure \
# This stage builds a dist tarball from the source
FROM alpine:edge as source-builder
RUN mkdir -p /src/alpine
COPY alpine/APKBUILD.in /src/alpine
RUN source /src/alpine/APKBUILD.in \
&& echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
&& apk add \
--no-cache \
--update-cache \
$makedepends \
gzip
COPY . /src
ARG PKGVER
RUN cd /src \
&& ./bootstrap.sh \
&& ./configure \
--enable-numeric-version \
--with-pkg-extra-version=_git$commit && \
make dist)
FROM alpine:3.7 as alpine-builder
RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk
ADD docker/alpine/alpine-build.sh /usr/bin/
ADD docker/alpine/builder /etc/sudoers.d
COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/
--with-pkg-extra-version="_git$PKGVER" \
&& make dist
# This stage builds an apk from the dist tarball
FROM alpine:edge as alpine-builder
# Don't use nocache here so that abuild can use the cache
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
&& apk add \
--update-cache \
abuild \
alpine-conf \
alpine-sdk \
&& setup-apkcache /var/cache/apk \
&& mkdir -p /pkgs/apk \
&& echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/
RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
USER builder
RUN /usr/bin/alpine-build.sh
FROM alpine:3.7
RUN cd /dist \
&& abuild-keygen -a -n \
&& abuild checksum \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
FROM alpine:edge
RUN mkdir -p /pkgs/apk
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
RUN apk add --no-cache tini
RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
&& apk add \
--no-cache \
--update-cache \
tini \
&& apk add \
--no-cache \
--allow-untrusted /pkgs/apk/*/*.apk \
&& rm -rf /pkgs
COPY docker/alpine/docker-start /usr/lib/frr/docker-start
ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]

View File

@ -1,11 +0,0 @@
#!/bin/sh
set -e
cd /dist
sudo apk --update add alpine-conf
sudo setup-apkcache /var/cache/apk
abuild-keygen -a -n
abuild checksum
abuild -r -P /pkgs/apk

View File

@ -1,17 +1,30 @@
#!/bin/sh
set -e
set -v
set -x
##
# commit must be converted to decimal
# Package version needs to be decimal
##
c=`git rev-parse --short=10 HEAD`
commit=`printf '%u\n' 0x$c`
docker build -f docker/alpine/Dockerfile \
--build-arg commit=$commit -t frr:alpine-$c .
id=`docker create frr:alpine-$c`
docker cp ${id}:/pkgs/ docker
docker rm $id
docker rmi frr:alpine-$c
GITREV="$(git rev-parse --short=10 HEAD)"
PKGVER="$(printf '%u\n' 0x$GITREV)"
docker build \
--pull \
--file=docker/alpine/Dockerfile \
--build-arg="PKGVER=$PKGVER" \
--tag="frr:alpine-builder-$GITREV" \
--target=alpine-builder \
.
CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")"
docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine
docker rm "${CONTAINER_ID}"
docker build \
--file=docker/alpine/Dockerfile \
--build-arg="PKGVER=$PKGVER" \
--tag="frr:alpine-$GITREV" \
.
docker rmi "frr:alpine-builder-$GITREV"

View File

@ -1 +0,0 @@
builder ALL=(ALL) NOPASSWD:ALL

View File

@ -6,5 +6,7 @@ set -e
# For volume mounts...
##
chown -R frr:frr /etc/frr
/etc/init.d/frr start
exec sleep 10000d
/usr/lib/frr/frrinit.sh start
# Sleep forever
exec tail -f /dev/null

View File

@ -314,7 +314,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
if (prefix->rij->count)
return EIGRP_FSM_KEEP_STATE;
zlog_info("All reply received\n");
zlog_info("All reply received");
if (head->reported_distance < prefix->fdistance) {
return EIGRP_FSM_EVENT_LR_FCS;
}
@ -344,7 +344,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
} else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
} else {
zlog_info("All reply received\n");
zlog_info("All reply received");
return EIGRP_FSM_EVENT_LR;
}
} else if (msg->packet_type == EIGRP_OPC_UPDATE
@ -366,7 +366,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
} else {
zlog_info("All reply received\n");
zlog_info("All reply received");
if (head->reported_distance
< prefix->fdistance) {
return EIGRP_FSM_EVENT_LR_FCS;
@ -390,7 +390,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
} else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
} else {
zlog_info("All reply received\n");
zlog_info("All reply received");
return EIGRP_FSM_EVENT_LR;
}
} else if (msg->packet_type == EIGRP_OPC_UPDATE

View File

@ -131,7 +131,7 @@ static int process_p2p_hello(struct iih_info *iih)
if (tw_adj) {
if (tw_adj->state > ISIS_THREEWAY_DOWN) {
if (isis->debugs & DEBUG_ADJ_PACKETS) {
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n",
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d",
iih->circuit->area->area_tag,
iih->circuit->interface->name,
tw_adj->state);
@ -144,7 +144,7 @@ static int process_p2p_hello(struct iih_info *iih)
|| tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
if (isis->debugs & DEBUG_ADJ_PACKETS) {
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n",
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.",
iih->circuit->area->area_tag,
iih->circuit->interface->name);
}
@ -1523,7 +1523,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
}
if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed)
zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n");
zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!");
retval = ISIS_OK;
out:

View File

@ -362,6 +362,10 @@ static int isis_zebra_read(int command, struct zclient *zclient,
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
if (api.prefix.family == AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
return 0;
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back

View File

@ -396,6 +396,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
struct interface *ifp;
switch (vrf_get_backend()) {
case VRF_BACKEND_UNKNOWN:
case VRF_BACKEND_NETNS:
ifp = if_lookup_by_name(name, vrf_id);
if (ifp)
@ -1279,6 +1280,11 @@ static int lib_interface_create(enum nb_event event,
vrf->name);
return NB_ERR_VALIDATION;
}
/* if VRF is netns or not yet known - init for instance
* then assumption is that passed config is exact
* then the user intent was not to use an other iface
*/
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
ifp = if_lookup_by_name_all_vrf(ifname);
if (ifp && ifp->vrf_id != vrf->vrf_id) {

View File

@ -991,6 +991,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE),
DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
DESC_ENTRY(ZEBRA_HELLO),
DESC_ENTRY(ZEBRA_CAPABILITIES),
DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE),
@ -1012,6 +1013,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_VRF_LABEL),
DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER),
DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
@ -1023,6 +1025,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_FEC_REGISTER),
DESC_ENTRY(ZEBRA_FEC_UNREGISTER),
DESC_ENTRY(ZEBRA_FEC_UPDATE),
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
@ -1057,6 +1062,11 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_IPSET_DESTROY),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE),
DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER),
DESC_ENTRY(ZEBRA_IPTABLE_ADD),
DESC_ENTRY(ZEBRA_IPTABLE_DELETE),
DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER),
DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
};
#undef DESC_ENTRY

View File

@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b)
return strcmp(a, b);
}
static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b)
{
if (!a && !b)
return 0;
if (a && !b)
return -1;
if (!a && b)
return 1;
return sockunion_cmp(a, b);
}
static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
{
int ret;
ret = sockunion_cmp(&nh1->addr, &nh2->addr);
ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
if (ret)
return ret;
@ -209,6 +223,9 @@ static void nhgl_delete(struct nexthop_hold *nh)
XFREE(MTYPE_TMP, nh->nhvrf_name);
if (nh->addr)
sockunion_free(nh->addr);
XFREE(MTYPE_TMP, nh);
}
@ -292,8 +309,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
if (intf)
nh->intf = XSTRDUP(MTYPE_TMP, intf);
nh->addr = *addr;
if (addr)
nh->addr = sockunion_dup(addr);
listnode_add_sort(nhgc->nhg_list, nh);
}
@ -308,7 +325,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
sockunion_cmp(addr, &nh->addr) == 0 &&
nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
nhgc_cmp_helper(intf, nh->intf) == 0)
break;
}
@ -320,13 +337,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
return;
list_delete_node(nhgc->nhg_list, node);
if (nh->nhvrf_name)
XFREE(MTYPE_TMP, nh->nhvrf_name);
if (nh->intf)
XFREE(MTYPE_TMP, nh->intf);
XFREE(MTYPE_TMP, nh);
nhgl_delete(nh);
}
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
@ -347,36 +358,45 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
nhop->vrf_id = vrf->vrf_id;
if (addr->sa.sa_family == AF_INET) {
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf) {
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
if (nhop->ifindex == IFINDEX_INTERNAL)
return false;
} else
nhop->type = NEXTHOP_TYPE_IPV4;
} else {
memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
if (intf) {
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
if (nhop->ifindex == IFINDEX_INTERNAL)
return false;
} else
nhop->type = NEXTHOP_TYPE_IPV6;
if (intf) {
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
if (nhop->ifindex == IFINDEX_INTERNAL)
return false;
}
if (addr) {
if (addr->sa.sa_family == AF_INET) {
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf)
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
else
nhop->type = NEXTHOP_TYPE_IPV4;
} else {
nhop->gate.ipv6 = addr->sin6.sin6_addr;
if (intf)
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
else
nhop->type = NEXTHOP_TYPE_IPV6;
}
} else
nhop->type = NEXTHOP_TYPE_IFINDEX;
return true;
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
"[no] nexthop\
<\
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
>\
[nexthop-vrf NAME$name]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
"v4 Address\n"
"v6 Address\n"
"Interface to use\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n")
{
@ -385,13 +405,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
struct nexthop *nh;
bool legal;
/*
* This is impossible to happen as that the cli parser refuses
* to let you get here without an addr, but the SA system
* does not understand this intricacy
*/
assert(addr);
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
if (nhop.type == NEXTHOP_TYPE_IPV6
@ -480,9 +493,10 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
{
char buf[100];
vty_out(vty, "nexthop ");
vty_out(vty, "nexthop");
vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
if (nh->addr)
vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf)));
if (nh->intf)
vty_out(vty, " %s", nh->intf);
@ -504,7 +518,7 @@ static int nexthop_group_write(struct vty *vty)
vty_out(vty, "nexthop-group %s\n", nhgc->name);
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
vty_out(vty, " ");
vty_out(vty, " ");
nexthop_group_write_nexthop_internal(vty, nh);
}
@ -526,7 +540,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
struct nexthop nhop;
struct nexthop *nh;
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
nhh->intf,
nhh->nhvrf_name))
continue;
@ -562,7 +576,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
struct nexthop nhop;
struct nexthop *nh;
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
nhh->intf,
nhh->nhvrf_name))
continue;
@ -600,7 +614,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
struct nexthop nhop;
if (!nexthop_group_parse_nexthop(
&nhop, &nhh->addr, nhh->intf,
&nhop, nhh->addr, nhh->intf,
nhh->nhvrf_name))
continue;

View File

@ -68,7 +68,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
struct nexthop_hold {
char *nhvrf_name;
union sockunion addr;
union sockunion *addr;
char *intf;
};

View File

@ -348,39 +348,58 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
* configurations. Given a new subtree, calculate all new YANG data nodes,
* excluding default leafs and leaf-lists. This is a recursive function.
*/
static void nb_config_diff_new_subtree(const struct lyd_node *dnode,
struct nb_config_cbs *changes)
static void nb_config_diff_created(const struct lyd_node *dnode,
struct nb_config_cbs *changes)
{
enum nb_operation operation;
struct lyd_node *child;
LY_TREE_FOR (dnode->child, child) {
enum nb_operation operation;
switch (child->schema->nodetype) {
case LYS_LEAF:
case LYS_LEAFLIST:
if (lyd_wd_default((struct lyd_node_leaf_list *)child))
break;
if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
operation = NB_OP_CREATE;
else if (nb_operation_is_valid(NB_OP_MODIFY,
child->schema))
operation = NB_OP_MODIFY;
else
continue;
nb_config_diff_add_change(changes, operation, child);
break;
case LYS_CONTAINER:
case LYS_LIST:
if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
nb_config_diff_add_change(changes, NB_OP_CREATE,
child);
nb_config_diff_new_subtree(child, changes);
break;
default:
switch (dnode->schema->nodetype) {
case LYS_LEAF:
case LYS_LEAFLIST:
if (lyd_wd_default((struct lyd_node_leaf_list *)dnode))
break;
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
operation = NB_OP_CREATE;
else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
operation = NB_OP_MODIFY;
else
return;
nb_config_diff_add_change(changes, operation, dnode);
break;
case LYS_CONTAINER:
case LYS_LIST:
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
/* Process child nodes recursively. */
LY_TREE_FOR (dnode->child, child) {
nb_config_diff_created(child, changes);
}
break;
default:
break;
}
}
static void nb_config_diff_deleted(const struct lyd_node *dnode,
struct nb_config_cbs *changes)
{
if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
struct lyd_node *child;
/*
* Non-presence containers need special handling since they
* don't have "destroy" callbacks. In this case, what we need to
* do is to call the "destroy" callbacks of their child nodes
* when applicable (i.e. optional nodes).
*/
LY_TREE_FOR (dnode->child, child) {
nb_config_diff_deleted(child, changes);
}
}
}
@ -399,42 +418,27 @@ static void nb_config_diff(const struct nb_config *config1,
for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
LYD_DIFFTYPE type;
struct lyd_node *dnode;
enum nb_operation operation;
type = diff->type[i];
switch (type) {
case LYD_DIFF_CREATED:
dnode = diff->second[i];
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
operation = NB_OP_CREATE;
else if (nb_operation_is_valid(NB_OP_MODIFY,
dnode->schema))
operation = NB_OP_MODIFY;
else
continue;
nb_config_diff_created(dnode, changes);
break;
case LYD_DIFF_DELETED:
dnode = diff->first[i];
operation = NB_OP_DESTROY;
nb_config_diff_deleted(dnode, changes);
break;
case LYD_DIFF_CHANGED:
dnode = diff->second[i];
operation = NB_OP_MODIFY;
nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
break;
case LYD_DIFF_MOVEDAFTER1:
case LYD_DIFF_MOVEDAFTER2:
default:
continue;
}
nb_config_diff_add_change(changes, operation, dnode);
if (type == LYD_DIFF_CREATED
&& CHECK_FLAG(dnode->schema->nodetype,
LYS_CONTAINER | LYS_LIST))
nb_config_diff_new_subtree(dnode, changes);
}
lyd_free_diff(diff);

View File

@ -708,19 +708,19 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
/* If we're already elevated, just return */
pthread_mutex_lock(&(privs->mutex));
if (++privs->refcount > 1) {
pthread_mutex_unlock(&(privs->mutex));
return privs;
{
if (++(privs->refcount) == 1) {
errno = 0;
if (privs->change(ZPRIVS_RAISE)) {
zlog_err("%s: Failed to raise privileges (%s)",
funcname, safe_strerror(errno));
}
errno = save_errno;
privs->raised_in_funcname = funcname;
}
}
pthread_mutex_unlock(&(privs->mutex));
errno = 0;
if (privs->change(ZPRIVS_RAISE)) {
zlog_err("%s: Failed to raise privileges (%s)",
funcname, safe_strerror(errno));
}
errno = save_errno;
privs->raised_in_funcname = funcname;
return privs;
}
@ -733,19 +733,20 @@ void _zprivs_lower(struct zebra_privs_t **privs)
/* Don't lower privs if there's another caller */
pthread_mutex_lock(&(*privs)->mutex);
if (--((*privs)->refcount) > 0) {
pthread_mutex_unlock(&(*privs)->mutex);
return;
{
if (--((*privs)->refcount) == 0) {
errno = 0;
if ((*privs)->change(ZPRIVS_LOWER)) {
zlog_err("%s: Failed to lower privileges (%s)",
(*privs)->raised_in_funcname,
safe_strerror(errno));
}
errno = save_errno;
(*privs)->raised_in_funcname = NULL;
}
}
pthread_mutex_unlock(&(*privs)->mutex);
errno = 0;
if ((*privs)->change(ZPRIVS_LOWER)) {
zlog_err("%s: Failed to lower privileges (%s)",
(*privs)->raised_in_funcname, safe_strerror(errno));
}
errno = save_errno;
(*privs)->raised_in_funcname = NULL;
*privs = NULL;
}

View File

@ -56,6 +56,7 @@ struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id);
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
static int vrf_backend;
static int vrf_backend_configured;
static struct zebra_privs_t *vrf_daemon_privs;
static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
@ -613,12 +614,15 @@ int vrf_is_backend_netns(void)
int vrf_get_backend(void)
{
if (!vrf_backend_configured)
return VRF_BACKEND_UNKNOWN;
return vrf_backend;
}
void vrf_configure_backend(int vrf_backend_netns)
{
vrf_backend = vrf_backend_netns;
vrf_backend_configured = 1;
}
int vrf_handler_create(struct vty *vty, const char *vrfname,
@ -662,7 +666,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
"VRF %u is already configured with VRF %s\n",
vrf->vrf_id, vrf->name);
else
zlog_info("VRF %u is already configured with VRF %s\n",
zlog_info("VRF %u is already configured with VRF %s",
vrf->vrf_id, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}

View File

@ -101,8 +101,9 @@ RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
DECLARE_QOBJ_TYPE(vrf)
/* Allow VRF with netns as backend */
#define VRF_BACKEND_VRF_LITE 0
#define VRF_BACKEND_NETNS 1
#define VRF_BACKEND_VRF_LITE 0
#define VRF_BACKEND_NETNS 1
#define VRF_BACKEND_UNKNOWN 2
extern struct vrf_id_head vrfs_by_id;
extern struct vrf_name_head vrfs_by_name;

View File

@ -629,7 +629,7 @@ void zclient_init(struct zclient *zclient, int redist_default,
}
if (zclient_debug)
zlog_debug("zclient_start is called");
zlog_debug("scheduling zclient connection");
zclient_event(ZCLIENT_SCHEDULE, zclient);
}
@ -2504,8 +2504,9 @@ static int zclient_read(struct thread *thread)
length -= ZEBRA_HEADER_SIZE;
if (zclient_debug)
zlog_debug("zclient 0x%p command 0x%x VRF %u\n",
(void *)zclient, command, vrf_id);
zlog_debug("zclient 0x%p command %s VRF %u",
(void *)zclient, zserv_command_string(command),
vrf_id);
switch (command) {
case ZEBRA_CAPABILITIES:
@ -2574,14 +2575,14 @@ static int zclient_read(struct thread *thread)
break;
case ZEBRA_NEXTHOP_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd nexthop update\n");
zlog_debug("zclient rcvd nexthop update");
if (zclient->nexthop_update)
(*zclient->nexthop_update)(command, zclient, length,
vrf_id);
break;
case ZEBRA_IMPORT_CHECK_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd import check update\n");
zlog_debug("zclient rcvd import check update");
if (zclient->import_check_update)
(*zclient->import_check_update)(command, zclient,
length, vrf_id);
@ -2608,7 +2609,7 @@ static int zclient_read(struct thread *thread)
break;
case ZEBRA_FEC_UPDATE:
if (zclient_debug)
zlog_debug("zclient rcvd fec update\n");
zlog_debug("zclient rcvd fec update");
if (zclient->fec_update)
(*zclient->fec_update)(command, zclient, length);
break;

View File

@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area)
if (IS_AREA_STUB(area)) {
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
zlog_debug("Stubbing out area for if %s\n", area->name);
zlog_debug("Stubbing out area for if %s", area->name);
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
} else if (IS_AREA_ENABLED(area)) {
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
zlog_debug("Normal area for if %s\n", area->name);
zlog_debug("Normal area for if %s", area->name);
OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
ospf6_asbr_send_externals_to_area(area);
}
@ -450,7 +450,7 @@ DEFUN (area_range,
range->path.u.cost_config = cost;
zlog_debug("%s: for prefix %s, flag = %x\n", __func__,
zlog_debug("%s: for prefix %s, flag = %x", __func__,
argv[idx_ipv6_prefixlen]->arg, range->flag);
if (range->rnode == NULL) {
ospf6_route_add(range, oa->range_table);

View File

@ -1006,7 +1006,7 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
zlog_debug("%s: Flooding AS-External LSA %s\n",
zlog_debug("%s: Flooding AS-External LSA %s",
__func__, lsa->name);
ospf6_flood_area(NULL, lsa, oa);
}

View File

@ -475,7 +475,7 @@ void ospf6_spf_calculation(uint32_t router_id,
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
if (lsa == NULL) {
if (IS_OSPF6_DEBUG_SPF(PROCESS))
zlog_debug("%s: No router LSA for area %s\n", __func__,
zlog_debug("%s: No router LSA for area %s", __func__,
oa->name);
return;
}

View File

@ -226,6 +226,9 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient,
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
return 0;
ifindex = api.nexthops[0].ifindex;
nexthop = &api.nexthops[0].gate.ipv6;

View File

@ -74,12 +74,12 @@ void api_opaque_lsa_print(struct lsa_header *data)
olsa = (struct opaque_lsa *)data;
opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE;
zlog_debug("apiserver_lsa_print: opaquelen=%d\n", opaquelen);
zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen);
for (i = 0; i < opaquelen; i++) {
zlog_debug("0x%x ", olsa->mydata[i]);
}
zlog_debug("\n");
zlog_debug(" ");
}
/* -----------------------------------------------------------
@ -242,7 +242,7 @@ const char *ospf_api_errname(int errcode)
void msg_print(struct msg *msg)
{
if (!msg) {
zlog_debug("msg_print msg=NULL!\n");
zlog_debug("msg_print msg=NULL!");
return;
}

View File

@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp)
/* zlog_warn for debugging */
zlog_warn("ospf_apiserver_del_if");
zlog_warn("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status,
zlog_warn("ifp name=%s status=%d index=%d", ifp->name, ifp->status,
ifp->ifindex);
oi = ospf_apiserver_if_lookup_by_ifp(ifp);
@ -2110,7 +2110,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa)
for (i = 0; i < opaquelen; i++) {
zlog_debug("0x%x ", olsa->data[i]);
}
zlog_debug("\n");
}
return;
}

View File

@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length,
oi = nbr->oi;
/* LS Request packet overflows interface MTU. */
/* LS Request packet overflows interface MTU
* delta is just number of bytes required for 1 LS Req
* ospf_packet_max will return the number of bytes can
* be accomodated without ospf header. So length+delta
* can be compared to ospf_packet_max
* to check if it can fit another lsreq in the same packet.
*/
if (*length + delta > ospf_packet_max(oi))
return 0;
@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s)
{
struct ospf_lsa *lsa;
uint16_t length = OSPF_LS_REQ_MIN_SIZE;
unsigned long delta = stream_get_endp(s) + 12;
unsigned long delta = 12;
struct route_table *table;
struct route_node *rn;
int i;
@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
assert(lsa->data);
/* Will it fit? */
if (length + delta + ntohs(lsa->data->length) > size_noauth)
/* Will it fit? Minimum it has to fit atleast one */
if ((length + delta + ntohs(lsa->data->length) > size_noauth) &&
(count > 0))
break;
/* Keep pointer to LS age. */
@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
{
struct listnode *node, *nnode;
uint16_t length = OSPF_LS_ACK_MIN_SIZE;
unsigned long delta = stream_get_endp(s) + 24;
unsigned long delta = OSPF_LSA_HEADER_SIZE;
struct ospf_lsa *lsa;
for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
assert(lsa);
if (length + delta > ospf_packet_max(oi))
/* LS Ack packet overflows interface MTU
* delta is just number of bytes required for
* 1 LS Ack(1 LS Hdr) ospf_packet_max will return
* the number of bytes can be accomodated without
* ospf header. So length+delta can be compared
* against ospf_packet_max to check if it can fit
* another ls header in the same packet.
*/
if ((length + delta) > ospf_packet_max(oi))
break;
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);

View File

@ -1372,14 +1372,14 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
}
else {
zlog_debug(" Segment Routing Algorithm TLV:\n");
zlog_debug(" Segment Routing Algorithm TLV:");
for (i = 0; i < ntohs(algo->header.length); i++)
switch (algo->value[i]) {
case 0:
zlog_debug(" Algorithm %d: SPF\n", i);
zlog_debug(" Algorithm %d: SPF", i);
break;
case 1:
zlog_debug(" Algorithm %d: Strict SPF\n", i);
zlog_debug(" Algorithm %d: Strict SPF", i);
break;
default:
zlog_debug(

View File

@ -901,7 +901,7 @@ static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type,
/* Sanity check, if LSA type unknwon
merley skip any LSA */
if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) {
zlog_debug("Strange request with LSA type %d\n", i);
zlog_debug("Strange request with LSA type %d", i);
return NULL;
}

View File

@ -1140,13 +1140,13 @@ ospf_rtrs_print (struct route_table *rtrs)
if (path->nexthop.s_addr == 0)
{
if (IS_DEBUG_OSPF_EVENT)
zlog_debug (" directly attached to %s\r\n",
zlog_debug (" directly attached to %s\r",
ifindex2ifname (path->ifindex), VRF_DEFAULT);
}
else
{
if (IS_DEBUG_OSPF_EVENT)
zlog_debug (" via %s, %s\r\n",
zlog_debug (" via %s, %s\r",
inet_ntoa (path->nexthop),
ifindex2ifname (path->ifindex), VRF_DEFAULT);
}

View File

@ -1600,7 +1600,7 @@ static int ospf_sr_update_schedule(struct thread *t)
monotime(&stop_time);
if (IS_DEBUG_OSPF_SR)
zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n",
zlog_debug("SR (%s): SPF Processing Time(usecs): %lld",
__func__,
(stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+ (stop_time.tv_usec - start_time.tv_usec));

View File

@ -3029,13 +3029,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
if (ospf->stub_router_startup_time
!= OSPF_STUB_ROUTER_UNCONFIGURED)
json_object_int_add(
json_vrf, "postStartEnabledMsecs",
ospf->stub_router_startup_time / 1000);
json_vrf, "postStartEnabledSecs",
ospf->stub_router_startup_time);
if (ospf->stub_router_shutdown_time
!= OSPF_STUB_ROUTER_UNCONFIGURED)
json_object_int_add(
json_vrf, "preShutdownEnabledMsecs",
ospf->stub_router_shutdown_time / 1000);
json_vrf, "preShutdownEnabledSecs",
ospf->stub_router_shutdown_time);
} else {
vty_out(vty,
" Stub router advertisement is configured\n");
@ -3511,8 +3511,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
json_object_int_add(json_interface_sub, "cost",
oi->output_cost);
json_object_int_add(
json_interface_sub, "transmitDelayMsecs",
1000 / OSPF_IF_PARAM(oi, transmit_delay));
json_interface_sub, "transmitDelaySecs",
OSPF_IF_PARAM(oi, transmit_delay));
json_object_string_add(json_interface_sub, "state",
lookup_msg(ospf_ism_state_msg,
oi->state, NULL));
@ -3616,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
if (OSPF_IF_PARAM(oi, fast_hello) == 0)
json_object_int_add(
json_interface_sub, "timerMsecs",
1000 / OSPF_IF_PARAM(oi, v_hello));
OSPF_IF_PARAM(oi, v_hello) * 1000);
else
json_object_int_add(
json_interface_sub, "timerMsecs",
1000 / OSPF_IF_PARAM(oi, fast_hello));
json_object_int_add(json_interface_sub,
"timerDeadMsecs",
1000 / OSPF_IF_PARAM(oi, v_wait));
"timerDeadSecs",
OSPF_IF_PARAM(oi, v_wait));
json_object_int_add(json_interface_sub,
"timerWaitMsecs",
1000 / OSPF_IF_PARAM(oi, v_wait));
"timerWaitSecs",
OSPF_IF_PARAM(oi, v_wait));
json_object_int_add(
json_interface_sub, "timerRetransmit",
1000 / OSPF_IF_PARAM(oi, retransmit_interval));
json_interface_sub, "timerRetransmitSecs",
OSPF_IF_PARAM(oi, retransmit_interval));
} else {
vty_out(vty, " Timer intervals configured,");
vty_out(vty, " Hello ");

View File

@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
static void
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg,
enum nexthop_types_t nh_afi);
enum nexthop_types_t nh_type);
/*
* Nexthop refcount.
@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
switch (pbrnc1->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
return true;
return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
return pbrnc1->nexthop->gate.ipv4.s_addr
@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(nhgc->name);
if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
struct interface *ifp;
ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
if (ifp)
pbr_nht_nexthop_interface_update(ifp);
}
}
void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
@ -274,7 +282,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
struct pbr_nexthop_group_cache *pnhgc;
struct pbr_nexthop_cache pnhc_find = {};
struct pbr_nexthop_cache *pnhc;
enum nexthop_types_t nh_afi = nhop->type;
enum nexthop_types_t nh_type = nhop->type;
/* find pnhgc by name */
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
@ -296,7 +304,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
if (pnhgc->nhh->count)
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
else
pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi);
pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
pbr_map_check_nh_group_change(nhgc->name);
}
@ -372,39 +380,53 @@ void pbr_nht_route_removed_for_table(uint32_t table_id)
* - AFI_MAX on error
*/
static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
enum nexthop_types_t nh_afi)
enum nexthop_types_t nh_type)
{
struct nexthop *nexthop;
afi_t install_afi = AFI_MAX;
bool v6, v4, bh;
if (nh_type) {
switch (nh_type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
return AFI_IP;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
return AFI_IP6;
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_BLACKHOLE:
return AFI_MAX;
}
}
v6 = v4 = bh = false;
if (!nh_afi) {
for (ALL_NEXTHOPS(nhg, nexthop)) {
nh_afi = nexthop->type;
for (ALL_NEXTHOPS(nhg, nexthop)) {
nh_type = nexthop->type;
switch (nh_type) {
case NEXTHOP_TYPE_IFINDEX:
break;
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
v6 = true;
install_afi = AFI_IP;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
v4 = true;
install_afi = AFI_IP6;
break;
case NEXTHOP_TYPE_BLACKHOLE:
bh = true;
break;
}
}
switch (nh_afi) {
case NEXTHOP_TYPE_IFINDEX:
break;
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
v6 = true;
install_afi = AFI_IP;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
v4 = true;
install_afi = AFI_IP6;
break;
case NEXTHOP_TYPE_BLACKHOLE:
bh = true;
/* Interface and/or blackhole nexthops only. */
if (!v4 && !v6)
install_afi = AFI_MAX;
break;
}
if (!bh && v6 && v4)
DEBUGD(&pbr_dbg_nht,
@ -423,9 +445,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg)
{
afi_t install_afi;
enum nexthop_types_t nh_afi = 0;
enum nexthop_types_t nh_type = 0;
install_afi = pbr_nht_which_afi(nhg, nh_afi);
install_afi = pbr_nht_which_afi(nhg, nh_type);
route_add(pnhgc, nhg, install_afi);
}
@ -433,11 +455,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
static void
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg,
enum nexthop_types_t nh_afi)
enum nexthop_types_t nh_type)
{
afi_t install_afi;
install_afi = pbr_nht_which_afi(nhg, nh_afi);
install_afi = pbr_nht_which_afi(nhg, nh_type);
pnhgc->installed = false;
pnhgc->valid = false;
@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
struct listnode *node;
struct pbr_map_interface *pmi;
struct nexthop *nh;
enum nexthop_types_t nh_afi = 0;
enum nexthop_types_t nh_type = 0;
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
@ -542,13 +564,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
pnhgc = hash_lookup(pbr_nhg_hash, &find);
nh = pbrms->nhg->nexthop;
nh_afi = nh->type;
nh_type = nh->type;
lup.nexthop = nh;
pnhc = hash_lookup(pnhgc->nhh, &lup);
pnhc->parent = NULL;
hash_release(pnhgc->nhh, pnhc);
pbr_nh_delete(&pnhc);
pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi);
pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
hash_release(pbr_nhg_hash, pnhgc);
@ -653,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
struct pbr_nht_individual {
struct zapi_route *nhr;
struct interface *ifp;
uint32_t valid;
};
@ -716,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr)
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
}
static void
pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
void *data)
{
struct pbr_nexthop_cache *pnhc = b->data;
struct pbr_nht_individual *pnhi = data;
bool old_valid;
old_valid = pnhc->valid;
if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
&& pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
pnhc->valid = !!if_is_up(pnhi->ifp);
DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
old_valid, pnhc->valid);
if (pnhc->valid)
pnhi->valid += 1;
}
static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
void *data)
{
struct pbr_nexthop_group_cache *pnhgc = b->data;
struct pbr_nht_individual pnhi;
bool old_valid;
old_valid = pnhgc->valid;
pnhi.ifp = data;
pnhi.valid = 0;
hash_iterate(pnhgc->nhh,
pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
/*
* If any of the specified nexthops are valid we are valid
*/
pnhgc->valid = !!pnhi.valid;
if (old_valid != pnhgc->valid)
pbr_map_check_nh_group_change(pnhgc->name);
}
void pbr_nht_nexthop_interface_update(struct interface *ifp)
{
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
ifp);
}
static uint32_t pbr_nhg_hash_key(void *arg)
{
struct pbr_nexthop_group_cache *nhgc =

View File

@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name);
*/
extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
/*
* When we get a callback from zebra about an interface status update.
*/
extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
extern void pbr_nht_init(void);
#endif

View File

@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
}
DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
"[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
"[no] set nexthop\
<\
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
>\
[nexthop-vrf NAME$name]",
NO_STR
"Set for the PBR-MAP\n"
"Specify one of the nexthops in this map\n"
"v4 Address\n"
"v6 Address\n"
"Interface to use\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n")
{
@ -255,45 +261,39 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
memset(&nhop, 0, sizeof(nhop));
nhop.vrf_id = vrf->vrf_id;
/*
* Make SA happy. CLIPPY is not going to give us a NULL
* addr.
*/
assert(addr);
if (addr->sa.sa_family == AF_INET) {
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf) {
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
if (nhop.ifindex == IFINDEX_INTERNAL) {
vty_out(vty,
"Specified Intf %s does not exist in vrf: %s\n",
intf, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}
} else
nhop.type = NEXTHOP_TYPE_IPV4;
} else {
memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
if (intf) {
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
if (nhop.ifindex == IFINDEX_INTERNAL) {
vty_out(vty,
"Specified Intf %s does not exist in vrf: %s\n",
intf, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}
} else {
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
vty_out(vty,
"Specified a v6 LL with no interface, rejecting\n");
return CMD_WARNING_CONFIG_FAILED;
}
nhop.type = NEXTHOP_TYPE_IPV6;
if (intf) {
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
if (nhop.ifindex == IFINDEX_INTERNAL) {
vty_out(vty,
"Specified Intf %s does not exist in vrf: %s\n",
intf, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}
}
if (addr) {
if (addr->sa.sa_family == AF_INET) {
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf)
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
else
nhop.type = NEXTHOP_TYPE_IPV4;
} else {
nhop.gate.ipv6 = addr->sin6.sin6_addr;
if (intf)
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
else {
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
vty_out(vty,
"Specified a v6 LL with no interface, rejecting\n");
return CMD_WARNING_CONFIG_FAILED;
}
nhop.type = NEXTHOP_TYPE_IPV6;
}
}
} else
nhop.type = NEXTHOP_TYPE_IFINDEX;
if (pbrms->nhg)
nh = nexthop_exists(pbrms->nhg, &nhop);
else {
@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
pbr_map_check(pbrms);
}
if (nhop.type == NEXTHOP_TYPE_IFINDEX) {
struct interface *ifp;
ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
if (ifp)
pbr_nht_nexthop_interface_update(ifp);
}
return CMD_SUCCESS;
}
@ -616,18 +624,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
if (pbrms->src)
vty_out(vty, " match src-ip %s\n",
vty_out(vty, " match src-ip %s\n",
prefix2str(pbrms->src, buff, sizeof(buff)));
if (pbrms->dst)
vty_out(vty, " match dst-ip %s\n",
vty_out(vty, " match dst-ip %s\n",
prefix2str(pbrms->dst, buff, sizeof(buff)));
if (pbrms->nhgrp_name)
vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
if (pbrms->nhg) {
vty_out(vty, " set ");
vty_out(vty, " set ");
nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
}

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