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 **/*.lo
**/*.so **/*.so
**/.libs **/.libs
docker/alpine/pkgs

View File

@ -175,13 +175,9 @@ EXTRA_DIST += \
python/clidef.py \ python/clidef.py \
python/clippy/__init__.py \ python/clippy/__init__.py \
\ \
redhat/frr.init \
redhat/frr.service \
redhat/daemons \
redhat/frr.logrotate \ redhat/frr.logrotate \
redhat/frr.pam \ redhat/frr.pam \
redhat/frr.spec \ redhat/frr.spec \
redhat/README.rpm_build.md \
\ \
snapcraft/snapcraft.yaml \ snapcraft/snapcraft.yaml \
snapcraft/README.snap_build.md \ 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" depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
acct autoconf automake bash 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 c-ares c-ares-dev ca-certificates cryptsetup-libs curl
device-mapper-libs expat fakeroot flex fortify-headers gdbm device-mapper-libs expat fakeroot flex fortify-headers gdbm
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
libgomp libisoburn libisofs libltdl libressl libssh2 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 mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
patch pax-utils pcre perl pkgconf python2 python2-dev readline patch pax-utils pcre perl pkgconf python2 python2-dev readline
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs 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" checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
source="$pkgname-$pkgver.tar.gz docker-start daemons" source="$pkgname-$pkgver.tar.gz"
builddir="$srcdir"/$pkgname-$pkgver builddir="$srcdir"/$pkgname-$pkgver
@ -60,8 +60,7 @@ package() {
cd "$builddir" cd "$builddir"
make DESTDIR="$pkgdir" install make DESTDIR="$pkgdir" install
install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir
install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
install -d "$pkgdir"/etc/init.d install -d "$pkgdir"/etc/init.d
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
} }

View File

@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session);
/* /*
* Prototypes * 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 uint32_t ptm_bfd_gen_ID(void);
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd); 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_init_handler(struct bfd_session *bs, int nstate);
static void bs_up_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 * 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; memset(key, 0, sizeof(*key));
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;
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; break;
} }
if (strcmp(bs->vrfname, bpc->bpc_vrfname)) key->mhop = mhop;
continue; if (ifname && ifname[0])
if (memcmp(&bs->mhop.peer, &bpc->bpc_peer, strlcpy(key->ifname, ifname, sizeof(key->ifname));
sizeof(bs->mhop.peer))) if (vrfname && vrfname[0])
continue; strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
if (memcmp(&bs->mhop.local, &bpc->bpc_local,
sizeof(bs->mhop.local)))
continue;
break;
}
if (bso == NULL)
bs = NULL;
return bs;
} }
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
{ {
struct bfd_session *bs; struct bfd_session *bs;
struct peer_label *pl; struct peer_label *pl;
struct interface *ifp; struct bfd_key key;
struct vrf *vrf;
struct bfd_mhop_key mhop;
struct bfd_shop_key shop;
/* Try to find label first. */ /* Try to find label first. */
if (bpc->bpc_has_label) { 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. */ /* Otherwise fallback to peer/local hash lookup. */
if (bpc->bpc_mhop) { gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
memset(&mhop, 0, sizeof(mhop)); bpc->bpc_localif, bpc->bpc_vrfname);
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;
mhop.vrfid = vrf->vrf_id; return bfd_key_lookup(key);
}
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);
} }
/* /*
@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
*/ */
int bfd_session_enable(struct bfd_session *bs) int bfd_session_enable(struct bfd_session *bs)
{ {
struct sockaddr_in6 *sin6;
struct interface *ifp = NULL; struct interface *ifp = NULL;
struct vrf *vrf = NULL; struct vrf *vrf = NULL;
int psock; 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 * If the interface or VRF doesn't exist, then we must register
* the session but delay its start. * the session but delay its start.
*/ */
if (bs->ifname[0] != 0) { if (bs->key.ifname[0]) {
ifp = if_lookup_by_name_all_vrf(bs->ifname); ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
if (ifp == NULL) { if (ifp == NULL) {
log_error( log_error(
"session-enable: specified interface doesn't exists."); "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); vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf == NULL) { if (vrf == NULL) {
log_error("session-enable: specified VRF doesn't exists."); log_error(
"session-enable: specified VRF doesn't exists.");
return 0; return 0;
} }
} }
if (bs->vrfname[0] != 0) { if (bs->key.vrfname[0]) {
vrf = vrf_lookup_by_name(bs->vrfname); vrf = vrf_lookup_by_name(bs->key.vrfname);
if (vrf == NULL) { if (vrf == NULL) {
log_error("session-enable: specified VRF doesn't exists."); log_error(
"session-enable: specified VRF doesn't exists.");
return 0; return 0;
} }
} }
@ -202,26 +158,15 @@ int bfd_session_enable(struct bfd_session *bs)
if (bs->vrf == NULL) if (bs->vrf == NULL)
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT); bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (bs->ifname[0] != 0 && if (bs->key.ifname[0]
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
bs->ifp = ifp; bs->ifp = ifp;
/* Set the IPv6 scope id for link-local addresses. */ /* Sanity check: don't leak open sockets. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { if (bs->sock != -1) {
sin6 = &bs->mhop.peer.sa_sin6; zlog_debug("session-enable: previous socket open");
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) close(bs->sock);
sin6->sin6_scope_id = bs->ifp != NULL bs->sock = -1;
? 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;
} }
/* /*
@ -232,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs)
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) { if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
psock = bp_peer_socket(bs); psock = bp_peer_socket(bs);
if (psock == -1) if (psock == -1)
return -1; return 0;
} else { } else {
psock = bp_peer_socketv6(bs); psock = bp_peer_socketv6(bs);
if (psock == -1) if (psock == -1)
return -1; return 0;
} }
/* /*
@ -247,25 +192,6 @@ int bfd_session_enable(struct bfd_session *bs)
bfd_recvtimer_update(bs); bfd_recvtimer_update(bs);
ptm_bfd_start_xmt_timer(bs, false); 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; return 0;
} }
@ -288,13 +214,6 @@ void bfd_session_disable(struct bfd_session *bs)
bfd_echo_recvtimer_delete(bs); bfd_echo_recvtimer_delete(bs);
bfd_xmttimer_delete(bs); bfd_xmttimer_delete(bs);
bfd_echo_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) 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) if (bs == NULL)
return NULL; return NULL;
/* Remove unused fields. */ switch (bs->key.family) {
switch (sa->sa_sin.sin_family) {
case AF_INET: case AF_INET:
sa->sa_sin.sin_port = 0; if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0) sizeof(sa->sa_sin.sin_addr)))
return bs; return NULL;
break; break;
case AF_INET6: case AF_INET6:
sa->sa_sin6.sin6_port = 0; if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0) sizeof(sa->sa_sin6.sin6_addr)))
return bs; return NULL;
break; break;
} }
return NULL; return bs;
} }
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, 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, ifindex_t ifindex, vrf_id_t vrfid,
bool is_mhop) bool is_mhop)
{ {
struct bfd_session *l_bfd = NULL; struct interface *ifp;
struct bfd_mhop_key mhop; struct vrf *vrf;
struct bfd_shop_key shop; struct bfd_key key;
/* Find our session using the ID signaled by the remote end. */ /* Find our session using the ID signaled by the remote end. */
if (cp->discrs.remote_discr) if (cp->discrs.remote_discr)
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr)); return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
/* Search for session without using discriminator. */ /* Search for session without using discriminator. */
if (is_mhop) { ifp = if_lookup_by_index(ifindex, vrfid);
memset(&mhop, 0, sizeof(mhop)); if (vrfid == VRF_DEFAULT) {
mhop.peer = *peer; /*
mhop.local = *local; * Don't use the default vrf, otherwise we won't find
mhop.vrfid = vrfid; * sessions that doesn't specify it.
*/
vrf = NULL;
} else
vrf = vrf_lookup_by_id(vrfid);
l_bfd = bfd_mhop_lookup(mhop); gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
} else { vrf ? vrf->name : NULL);
memset(&shop, 0, sizeof(shop));
shop.peer = *peer;
shop.ifindex = ifindex;
l_bfd = bfd_shop_lookup(shop);
}
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */ /* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
return l_bfd; return bfd_key_lookup(key);
} }
int bfd_xmt_cb(struct thread *t) 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_session_disable(bs);
bfd_key_delete(bs->key);
bfd_id_delete(bs->discrs.my_discr);
/* Remove observer if any. */ /* Remove observer if any. */
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
if (bso->bso_bs != bs) 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. * start. See `bfd_session_enable` for more information.
*/ */
if (bpc->bpc_has_localif) 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) if (bpc->bpc_has_vrfname)
strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname)); strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
sizeof(bfd->key.vrfname));
/* Add observer if we have moving parts. */
if (bfd->ifname[0] || bfd->vrfname[0])
bs_observer_add(bfd);
/* Copy remaining data. */ /* Copy remaining data. */
if (bpc->bpc_ipv4 == false) if (bpc->bpc_ipv4 == false)
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
if (bpc->bpc_mhop) { bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH); switch (bfd->key.family) {
bfd->mhop.peer = bpc->bpc_peer; case AF_INET:
bfd->mhop.local = bpc->bpc_local; memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
} else { sizeof(bpc->bpc_peer.sa_sin.sin_addr));
bfd->shop.peer = bpc->bpc_peer; 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; if (bpc->bpc_mhop)
bfd->local_address = bpc->bpc_local; 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. */ /* Try to enable session and schedule for packet receive/send. */
if (bfd_session_enable(bfd) == -1) { if (bfd_session_enable(bfd) == -1) {
@ -774,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
return NULL; 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. */ /* Apply other configurations. */
_bfd_session_update(bfd, bpc); _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); 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]; static char buf[256];
char addr_buf[INET6_ADDRSTRLEN];
int pos; int pos;
bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no"); 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", pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
satostr(&bs->shop.peer)); inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
sizeof(addr_buf)));
if (bs->local_address.sa_sin.sin_family) pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
pos += snprintf(buf + pos, sizeof(buf) - pos, inet_ntop(bs->key.family, &bs->key.local, addr_buf,
" local:%s", sizeof(addr_buf)));
satostr(&bs->local_address)); if (bs->key.vrfname[0])
pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
if (bs->shop.ifindex) bs->key.vrfname);
snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u", if (bs->key.ifname[0])
bs->shop.ifindex); pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
} bs->key.ifname);
return buf; return buf;
} }
@ -1255,16 +1187,25 @@ int bs_observer_add(struct bfd_session *bs)
{ {
struct bfd_session_observer *bso; 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_bs = bs;
bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
if (bso->bso_isinterface) if (bso->bso_isinterface)
strlcpy(bso->bso_entryname, bs->ifname, strlcpy(bso->bso_entryname, bs->key.ifname,
sizeof(bso->bso_entryname)); sizeof(bso->bso_entryname));
else else
strlcpy(bso->bso_entryname, bs->vrfname, strlcpy(bso->bso_entryname, bs->key.vrfname,
sizeof(bso->bso_entryname)); 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); TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
return 0; return 0;
@ -1276,21 +1217,59 @@ void bs_observer_del(struct bfd_session_observer *bso)
XFREE(MTYPE_BFDD_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. * BFD hash data structures to find sessions.
*/ */
static struct hash *bfd_id_hash; static struct hash *bfd_id_hash;
static struct hash *bfd_shop_hash; static struct hash *bfd_key_hash;
static struct hash *bfd_mhop_hash;
static unsigned int bfd_id_hash_do(void *p); static unsigned int bfd_id_hash_do(void *p);
static unsigned int bfd_shop_hash_do(void *p); static unsigned int bfd_key_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 void _bfd_free(struct hash_bucket *hb, static void _bfd_free(struct hash_bucket *hb,
void *arg __attribute__((__unused__))); 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. */ /* 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; 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; 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. * 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); 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; 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); /* Handle cases where local-address is optional. */
if (bsp == NULL && bs.shop.ifindex != 0) { if (bsp == NULL && bs.key.family == AF_INET) {
/* memset(&bs.key.local, 0, sizeof(bs.key.local));
* Since the local interface spec is optional, try bsp = hash_lookup(bfd_key_hash, &bs);
* searching the key without it as well. }
*/
_shop_key2(&bs, &shop); /* Handle cases where ifname is optional. */
bsp = hash_lookup(bfd_shop_hash, &bs); 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; 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. * Delete functions.
* *
@ -1440,31 +1367,18 @@ struct bfd_session *bfd_id_delete(uint32_t id)
return hash_release(bfd_id_hash, &bs); 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; struct bfd_session bs, *bsp;
_shop_key(&bs, &shop); bs.key = key;
bsp = hash_release(bfd_shop_hash, &bs); bsp = hash_lookup(bfd_key_hash, &bs);
if (bsp == NULL && shop.ifindex != 0) { if (bsp == NULL && key.ifname[0]) {
/* memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
* Since the local interface spec is optional, try bsp = hash_lookup(bfd_key_hash, &bs);
* searching the key without it as well.
*/
_shop_key2(&bs, &shop);
bsp = hash_release(bfd_shop_hash, &bs);
} }
return bsp; return hash_release(bfd_key_hash, 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);
} }
/* Iteration functions. */ /* Iteration functions. */
@ -1473,14 +1387,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg)
hash_iterate(bfd_id_hash, hif, 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); hash_iterate(bfd_key_hash, hif, arg);
}
void bfd_mhop_iterate(hash_iter_func hif, void *arg)
{
hash_iterate(bfd_mhop_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); 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); return (hash_get(bfd_key_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);
} }
void bfd_initialize(void) void bfd_initialize(void)
{ {
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp, bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
"BFD discriminator hash"); "BFD session discriminator hash");
bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp, bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
"BFD single hop hash"); "BFD session hash");
bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
"BFD multihop hop hash");
} }
static void _bfd_free(struct hash_bucket *hb, static void _bfd_free(struct hash_bucket *hb,
@ -1532,11 +1434,9 @@ void bfd_shutdown(void)
* assert() here to make sure it really happened. * assert() here to make sure it really happened.
*/ */
bfd_id_iterate(_bfd_free, NULL); bfd_id_iterate(_bfd_free, NULL);
assert(bfd_shop_hash->count == 0); assert(bfd_key_hash->count == 0);
assert(bfd_mhop_hash->count == 0);
/* Now free the hashes themselves. */ /* Now free the hashes themselves. */
hash_free(bfd_id_hash); hash_free(bfd_id_hash);
hash_free(bfd_shop_hash); hash_free(bfd_key_hash);
hash_free(bfd_mhop_hash);
} }

View File

@ -173,15 +173,13 @@ enum bfd_session_flags {
#define BFD_CHECK_FLAG(field, flag) (field & flag) #define BFD_CHECK_FLAG(field, flag) (field & flag)
/* BFD session hash keys */ /* BFD session hash keys */
struct bfd_shop_key { struct bfd_key {
struct sockaddr_any peer; uint16_t family;
ifindex_t ifindex; uint8_t mhop;
}; struct in6_addr peer;
struct in6_addr local;
struct bfd_mhop_key { char ifname[MAXNAMELEN];
struct sockaddr_any peer; char vrfname[MAXNAMELEN];
struct sockaddr_any local;
vrf_id_t vrfid;
}; };
struct bfd_session_stats { struct bfd_session_stats {
@ -227,19 +225,14 @@ struct bfd_session {
uint8_t polling; uint8_t polling;
/* This and the localDiscr are the keys to state info */ /* This and the localDiscr are the keys to state info */
struct bfd_key key;
struct peer_label *pl; 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_address;
struct sockaddr_any local_ip;
struct interface *ifp; struct interface *ifp;
struct vrf *vrf; struct vrf *vrf;
char ifname[MAXNAMELEN];
char vrfname[MAXNAMELEN]; int sock;
/* BFD session flags */ /* BFD session flags */
enum bfd_session_flags flags; enum bfd_session_flags flags;
@ -281,7 +274,11 @@ struct bfd_state_str_list {
struct bfd_session_observer { struct bfd_session_observer {
struct bfd_session *bso_bs; struct bfd_session *bso_bs;
bool bso_isinterface; bool bso_isinterface;
bool bso_isaddress;
union {
char bso_entryname[MAXNAMELEN]; char bso_entryname[MAXNAMELEN];
struct prefix bso_addr;
};
TAILQ_ENTRY(bfd_session_observer) bso_entry; TAILQ_ENTRY(bfd_session_observer) bso_entry;
}; };
@ -531,38 +528,28 @@ const char *satostr(struct sockaddr_any *sa);
const char *diag2str(uint8_t diag); const char *diag2str(uint8_t diag);
int strtosa(const char *addr, struct sockaddr_any *sa); int strtosa(const char *addr, struct sockaddr_any *sa);
void integer2timestr(uint64_t time, char *buf, size_t buflen); 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); int bs_observer_add(struct bfd_session *bs);
void bs_observer_del(struct bfd_session_observer *bso); 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 */ /* BFD hash data structures interface */
void bfd_initialize(void); void bfd_initialize(void);
void bfd_shutdown(void); void bfd_shutdown(void);
struct bfd_session *bfd_id_lookup(uint32_t id); struct bfd_session *bfd_id_lookup(uint32_t id);
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop); struct bfd_session *bfd_key_lookup(struct bfd_key key);
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_id_delete(uint32_t id); struct bfd_session *bfd_id_delete(uint32_t id);
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop); struct bfd_session *bfd_key_delete(struct bfd_key key);
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);
bool bfd_id_insert(struct bfd_session *bs); bool bfd_id_insert(struct bfd_session *bs);
bool bfd_shop_insert(struct bfd_session *bs); bool bfd_key_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);
typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg); typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
void bfd_id_iterate(hash_iter_func hif, void *arg); void bfd_id_iterate(hash_iter_func hif, void *arg);
void bfd_shop_iterate(hash_iter_func hif, void *arg); void bfd_key_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);
/* Export callback functions for `event.c`. */ /* Export callback functions for `event.c`. */
extern struct thread_master *master; 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_xmt_cb(struct thread *t);
int bfd_echo_xmt_cb(struct thread *t); int bfd_echo_xmt_cb(struct thread *t);
extern struct in6_addr zero_addr;
/* /*
* bfdd_vty.c * 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)) { if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
memset(&sin6, 0, sizeof(sin6)); memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6; 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 = sin6.sin6_port =
(port) ? *port (port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) : (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 { } else {
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; 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 = sin.sin_port =
(port) ? *port (port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) : (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) void ptm_bfd_echo_snd(struct bfd_session *bfd)
{ {
struct sockaddr_any *sa; struct sockaddr *sa;
socklen_t salen; socklen_t salen;
int sd; int sd;
struct bfd_echo_pkt bep; 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.len = BFD_ECHO_PKT_LEN;
bep.my_discr = htonl(bfd->discrs.my_discr); 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)) { if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
sd = bglobal.bg_echov6; 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); sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6); sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sa = (struct sockaddr_any *)&sin6; sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6); salen = sizeof(sin6);
} else { } else {
sd = bglobal.bg_echo; 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); sin.sin_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin); sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sa = (struct sockaddr_any *)&sin; sa = (struct sockaddr *)&sin;
salen = sizeof(sin); salen = sizeof(sin);
} }
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
(struct sockaddr *)sa, salen) salen)
== -1) == -1)
return; return;
@ -602,8 +610,8 @@ int bfd_recv_cb(struct thread *t)
bfd->mh_ttl, BFD_TTL_VAL); bfd->mh_ttl, BFD_TTL_VAL);
return 0; return 0;
} }
} else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) { } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
bfd->local_ip = local; bfd->local_address = local;
} }
/* /*
@ -917,25 +925,26 @@ int bp_peer_socket(const struct bfd_session *bs)
return -1; return -1;
} }
if (bs->shop.ifindex != IFINDEX_INTERNAL) { if (bs->key.ifname[0]) {
if (bp_bind_dev(sd, bs->ifp->name) != 0) { if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd); close(sd);
return -1; return -1;
} }
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
bs->mhop.vrfid != VRF_DEFAULT) { && bs->key.vrfname[0]) {
if (bp_bind_dev(sd, bs->vrf->name) != 0) { if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd); close(sd);
return -1; return -1;
} }
} }
/* Find an available source port in the proper range */ /* 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; sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin); sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ #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) if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
sin.sin_addr.s_addr = INADDR_ANY; 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 */ /* 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; sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6); sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ #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 (bs->key.ifname[0]) {
if (bp_bind_dev(sd, bs->ifp->name) != 0) { if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd); close(sd);
return -1; return -1;
} }
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
bs->mhop.vrfid != VRF_DEFAULT) { && bs->key.vrfname[0]) {
if (bp_bind_dev(sd, bs->vrf->name) != 0) { if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd); close(sd);
return -1; 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 *local_str, const char *ifname,
const char *vrfname); const char *vrfname);
/* /*
* Commands definition. * 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) static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
{ {
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { char addr_buf[INET6_ADDRSTRLEN];
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
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, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
if (bs->vrfname[0]) if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
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", vty_out(vty, " local-address %s",
satostr(&bs->local_address)); inet_ntop(bs->key.family, &bs->key.local, addr_buf,
if (bs->ifname[0]) sizeof(addr_buf)));
vty_out(vty, " interface %s", bs->ifname);
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"); vty_out(vty, "\n");
}
if (bs->pl) if (bs->pl)
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); 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) static struct json_object *_peer_json_header(struct bfd_session *bs)
{ {
struct json_object *jo = json_object_new_object(); 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_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer)); else
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
if (bs->vrfname[0])
json_object_string_add(jo, "vrf", bs->vrfname);
} else {
json_object_boolean_false_add(jo, "multihop"); 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, "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", json_object_string_add(jo, "local",
satostr(&bs->local_address)); inet_ntop(bs->key.family, &bs->key.local,
if (bs->ifname[0]) addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "interface", bs->ifname);
} 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) if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label); 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) static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
{ {
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { char addr_buf[INET6_ADDRSTRLEN];
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
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, " multihop");
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
if (bs->vrfname[0]) if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
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", vty_out(vty, " local-address %s",
satostr(&bs->local_address)); inet_ntop(bs->key.family, &bs->key.local, addr_buf,
if (bs->ifname[0]) sizeof(addr_buf)));
vty_out(vty, " interface %s", bs->ifname);
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"); vty_out(vty, "\n");
}
if (bs->sock == -1) 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) if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult); 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) static int bfdd_peer_write_config(struct vty *vty)
{ {
struct bfd_session_observer *bso;
bfd_id_iterate(_bfdd_peer_write_config_iter, vty); 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; return 1;
} }

View File

@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo,
log_debug("\tpeer-label: %s", sval); log_debug("\tpeer-label: %s", sval);
/* Translate the label into BFD address keys. */ /* Translate the label into BFD address keys. */
bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6); bs_to_bpc(pl->pl_bs, bpc);
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));
}
}
return 0; 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) static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
{ {
char addr_buf[INET6_ADDRSTRLEN];
/* Add peer 'key' information. */ /* Add peer 'key' information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
json_object_boolean_true_add(jo, "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)) { if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
json_object_boolean_true_add(jo, "multihop"); json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer-address", 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", json_object_string_add(jo, "local-address",
satostr(&bs->mhop.local)); inet_ntop(bs->key.family, &bs->key.local,
if (bs->vrfname[0]) addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "vrf-name", bs->vrfname); if (bs->key.vrfname[0])
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
} else { } else {
json_object_boolean_false_add(jo, "multihop"); json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address", json_object_string_add(jo, "peer-address",
satostr(&bs->shop.peer)); inet_ntop(bs->key.family, &bs->key.peer,
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "local-address", if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
satostr(&bs->local_address)); json_object_string_add(
if (bs->ifname[0]) 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", json_object_string_add(jo, "local-interface",
bs->ifname); bs->key.ifname);
} }
if (bs->pl) if (bs->pl)

View File

@ -55,7 +55,7 @@ static struct zclient *zclient;
/* /*
* Prototypes * 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 void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
static int _ptm_msg_read(struct stream *msg, int command, 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) #define DEBUG_PRINTBPC(bpc)
#endif /* BFD_DEBUG */ #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: case AF_INET:
stream_putc(msg, sa->sa_sin.sin_family); stream_put(msg, addr, sizeof(struct in_addr));
stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
stream_putc(msg, 32); stream_putc(msg, 32);
break; break;
case AF_INET6: case AF_INET6:
stream_putc(msg, sa->sa_sin6.sin6_family); stream_put(msg, addr, sizeof(struct in6_addr));
stream_put(msg, &sa->sa_sin6.sin6_addr,
sizeof(sa->sa_sin6.sin6_addr));
stream_putc(msg, 128); stream_putc(msg, 128);
break; break;
default: default:
return -1; assert(0);
break;
} }
return 0; 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) int ptm_bfd_notify(struct bfd_session *bs)
{ {
struct stream *msg; struct stream *msg;
struct sockaddr_any sac;
bs->stats.znotification++; bs->stats.znotification++;
@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
stream_putl(msg, IFINDEX_INTERNAL); stream_putl(msg, IFINDEX_INTERNAL);
/* BFD destination prefix information. */ /* BFD destination prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
_ptm_msg_address(msg, &bs->mhop.peer);
else
_ptm_msg_address(msg, &bs->shop.peer);
/* BFD status */ /* BFD status */
switch (bs->ses_state) { switch (bs->ses_state) {
@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
} }
/* BFD source prefix information. */ /* BFD source prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { _ptm_msg_address(msg, bs->key.family, &bs->key.local);
_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);
}
}
/* Write packet size. */ /* Write packet size. */
stream_putw_at(msg, 0, stream_get_endp(msg)); 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, static int _ptm_msg_read(struct stream *msg, int command,
struct bfd_peer_cfg *bpc, struct ptm_client **pc) struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{ {
struct interface *ifp;
uint32_t pid; uint32_t pid;
uint8_t ttl __attribute__((unused)); uint8_t ttl __attribute__((unused));
size_t ifnamelen; size_t ifnamelen;
@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command,
if (bpc->bpc_has_localif) { if (bpc->bpc_has_localif) {
STREAM_GET(bpc->bpc_localif, msg, ifnamelen); STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
bpc->bpc_localif[ifnamelen] = 0; 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. */ /* Interface name mismatch. */
bs = bso->bso_bs; bs = bso->bso_bs;
if (strcmp(ifp->name, bs->ifname)) if (strcmp(ifp->name, bs->key.ifname))
continue; continue;
/* Skip enabled sessions. */ /* Skip enabled sessions. */
if (bs->sock != -1) if (bs->sock != -1)
@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
/* Interface name mismatch. */ /* Interface name mismatch. */
bs = bso->bso_bs; bs = bso->bso_bs;
if (strcmp(ifp->name, bs->ifname)) if (strcmp(ifp->name, bs->key.ifname))
continue; continue;
/* Skip disabled sessions. */ /* Skip disabled sessions. */
if (bs->sock == -1) if (bs->sock == -1)
@ -691,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)),
return 0; 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) void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{ {
zclient = zclient_new(master, &zclient_options_default); 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. */ /* Learn about interface VRF. */
zclient->interface_vrf_update = bfdd_interface_vrf_update; 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) 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 " : "", CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
peer->host); 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); stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
if (!peer->nexthop.ifp) { 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); peer->host);
return BGP_ATTR_PARSE_WITHDRAW; 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); stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
if (!peer->nexthop.ifp) { 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); peer->host);
return BGP_ATTR_PARSE_WITHDRAW; 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; attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
} }
if (!peer->nexthop.ifp) { 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); peer->host);
return BGP_ATTR_PARSE_WITHDRAW; return BGP_ATTR_PARSE_WITHDRAW;
} }

View File

@ -48,6 +48,7 @@
#include "bgpd/bgp_zebra.h" #include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_addpath.h" #include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
/* /*
* Definitions and external declarations. * 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. */ /* Perform route selection and update zebra, if required. */
bgp_process(bgp_vrf, rn, afi, safi); bgp_process(bgp_vrf, rn, afi, safi);
/* Process for route leaking. */
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
return ret; return ret;
} }
@ -2668,6 +2672,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
if (!pi) if (!pi)
return 0; 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); bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
/* Mark entry for deletion */ /* Mark entry for deletion */
@ -2940,6 +2947,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
return 0; 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 * Install or uninstall mac-ip routes are appropriate for this
* particular VRF. * particular VRF.
@ -2996,6 +3038,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
continue; continue;
if (is_route_matching_for_vrf(bgp_vrf, pi)) { if (is_route_matching_for_vrf(bgp_vrf, pi)) {
if (bgp_evpn_route_rmac_self_check(
bgp_vrf, evp, pi))
continue;
if (install) if (install)
ret = install_evpn_route_entry_in_vrf( ret = install_evpn_route_entry_in_vrf(
bgp_vrf, evp, pi); 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]; table = bgp_vrf->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { 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. */ /* TODO: Support for AddPath for EVPN. */
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) 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, bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
afi, safi); afi, safi);
break; break;
@ -4294,12 +4342,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
table = bgp_vrf->rib[afi][safi]; table = bgp_vrf->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
/* Need to identify the "selected" route entry to use its /* 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. * TODO: Support for AddPath for EVPN.
*/ */
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& (!pi->extra || !pi->extra->parent)) { && is_route_injectable_into_evpn(pi)) {
/* apply the route-map */ /* apply the route-map */
if (bgp_vrf->adv_cmd_rmap[afi][safi].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) 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); 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) !ri->extra->parent)
return 0; return 0;
/* See if the parent is of family L2VPN/EVPN */ /* Determine parent recursively */
parent_ri = (struct bgp_path_info *)ri->extra->parent; 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; rn = parent_ri->net;
if (!rn) if (!rn)
return 0; return 0;
@ -102,6 +107,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
return 0; 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, extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
struct prefix *p, struct prefix *p,
struct attr *src_attr, afi_t afi, struct attr *src_attr, afi_t afi,

View File

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

View File

@ -3369,6 +3369,7 @@ DEFUN (bgp_evpn_advertise_type5,
} }
/* advertise type-5 routes */ /* advertise type-5 routes */
if (advertise_type5_routes(bgp_vrf, afi))
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi); bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

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 status start timer is on unless peer is shutdown or peer is
inactive. All other timer must be turned off */ inactive. All other timer must be turned off */
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer) 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); BGP_TIMER_OFF(peer->t_start);
} else { } else {
BGP_TIMER_ON(peer->t_start, bgp_start_timer, BGP_TIMER_ON(peer->t_start, bgp_start_timer,
@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer)
return 0; 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)) if (bgp_debug_neighbor_events(peer))
flog_err( flog_err(
EC_BGP_FSM, EC_BGP_FSM,

View File

@ -284,9 +284,9 @@ static int bgp_vrf_enable(struct vrf *vrf)
bgp_vrf_link(bgp, vrf); bgp_vrf_link(bgp, vrf);
bgp_handle_socket(bgp, vrf, old_vrf_id, true); 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) if (old_vrf_id != bgp->vrf_id)
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_redistribute_redo(bgp);
bgp_instance_up(bgp); bgp_instance_up(bgp);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); 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 /* We have instance configured, unlink from VRF and make it
* "down". */ * "down". */
bgp_vrf_unlink(bgp, vrf); 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) 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); bgp_instance_down(bgp);
} }

View File

@ -46,6 +46,7 @@
#include "bgpd/bgp_zebra.h" #include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h" #include "bgpd/bgp_nht.h"
#include "bgpd/bgp_evpn.h"
#if ENABLE_BGP_VNC #if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h" #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) if (bpi->extra && bpi->extra->bgp_orig)
bgp_nexthop = 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; nh_valid = 1;
else else
/* /*
@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
* No nexthop tracking for redistributed routes because * No nexthop tracking for redistributed routes because
* their originating protocols will do the tracking and * their originating protocols will do the tracking and
* withdraw those routes if the nexthops become unreachable * 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; nh_valid = 1;
else else
/* /*
@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
return; return;
} }
/* loop check - should not be an imported route. */ /* Is this route exportable into the VPN table? */
if (path_vrf->extra && path_vrf->extra->bgp_orig) if (!is_route_injectable_into_vpn(path_vrf))
return; return;
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug) if (debug)
zlog_debug("%s: %s skipping: %s", __func__, 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); 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) if (!bgp_vpn)
return; return;
@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
return; 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 (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug) if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg); 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) { == bgp_vrf) {
/* delete route */ /* delete route */
if (debug) if (debug)
zlog_debug("%s: deleting it\n", zlog_debug("%s: deleting it",
__func__); __func__);
bgp_aggregate_decrement(bgp_vpn, &bn->p, bgp_aggregate_decrement(bgp_vpn, &bn->p,
bpi, afi, safi); 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; for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
bpi = bpi->next) { 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 */ /* delete route */
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi, 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 void vpn_policy_routemap_event(const char *rmap_name);
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey); 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 */ /* advertise/withdraw type-5 routes */
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
if (advertise_type5_routes(bgp, afi) && new_select && if (advertise_type5_routes(bgp, afi) &&
(!new_select->extra || !new_select->extra->parent)) { new_select &&
is_route_injectable_into_evpn(new_select)) {
/* apply the route-map */ /* apply the route-map */
if (bgp->adv_cmd_rmap[afi][safi].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); afi, safi);
} }
} else if (advertise_type5_routes(bgp, afi) && old_select && } else if (advertise_type5_routes(bgp, afi) &&
(!old_select->extra || !old_select->extra->parent)) old_select &&
is_route_injectable_into_evpn(old_select))
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); 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; 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. */ /* Prototypes. */
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi, extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi); 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", "Processing route_map %s update on advertise type5 route command",
rmap_name); rmap_name);
if (route_update) { if (route_update && advertise_type5_routes(bgp, afi)) {
bgp_evpn_withdraw_type5_routes(bgp, afi, safi); bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
bgp_evpn_advertise_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 struct cache *find_cache(const uint8_t preference);
static int add_tcp_cache(const char *host, const char *port, static int add_tcp_cache(const char *host, const char *port,
const uint8_t preference); 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_synchronized(void);
static int is_running(void); static int is_running(void);
static void route_match_free(void *rule); static void route_match_free(void *rule);
@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference)
return NULL; 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]; 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 rpki_for_each_record_arg *arg = data;
struct vty *vty = arg->vty; struct vty *vty = arg->vty;
(*arg->prefix_amount)++; (*arg->prefix_amount)++;
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip)); print_record(record, vty);
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
record->max_len, record->asn);
} }
static struct rtr_mgr_group *get_groups(void) 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"); vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
arg.prefix_amount = &number_of_ipv4_prefixes; 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; 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 IPv4 Prefixes: %u\n", number_of_ipv4_prefixes);
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_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; 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, DEFUN (show_rpki_cache_server,
show_rpki_cache_server_cmd, show_rpki_cache_server_cmd,
"show rpki cache-server", "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_prefix_table_cmd);
install_element(ENABLE_NODE, &show_rpki_cache_connection_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_cache_server_cmd);
install_element(ENABLE_NODE, &show_rpki_prefix_cmd);
/* Install debug commands */ /* Install debug commands */
install_element(CONFIG_NODE, &debug_rpki_cmd); install_element(CONFIG_NODE, &debug_rpki_cmd);

View File

@ -2055,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw,
return CMD_SUCCESS; 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 */ /* "bgp graceful-shutdown" configuration */
DEFUN (bgp_graceful_shutdown, DEFUN (bgp_graceful_shutdown,
bgp_graceful_shutdown_cmd, 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); 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); ret = str2sockunion(peer_str, &su);
if (ret < 0) { 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, ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi,
safi); 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); ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
if (ret < 0) { if (ret < 0) {
vty_out(vty, vty_out(vty,
"%% Create the peer-group or interface first or specify \"interface\" keyword\n"); "%% Create the peer-group or interface first\n");
vty_out(vty, "%% if using an unnumbered interface neighbor\n");
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
return CMD_SUCCESS; return CMD_SUCCESS;
@ -3251,7 +3233,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
/* look up for neighbor by interface name config. */ /* look up for neighbor by interface name config. */
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg); peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
if (peer) { if (peer) {
peer_as_change(peer, 0, AS_SPECIFIED); peer_as_change(peer, 0, AS_UNSPECIFIED);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -8031,7 +8013,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json, "ribMemory", json, "ribMemory",
ents * sizeof(struct bgp_node)); 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, "peerCount", ents);
json_object_int_add(json, "peerMemory", json_object_int_add(json, "peerMemory",
ents * sizeof(struct peer)); 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))); bgp_node)));
/* Peer related usage */ /* Peer related usage */
ents = listcount(bgp->peer); ents = bgp->af_peer_count[afi][safi];
vty_out(vty, "Peers %ld, using %s of memory\n", vty_out(vty, "Peers %ld, using %s of memory\n",
ents, ents,
mtype_memstr( mtype_memstr(
@ -8522,7 +8504,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi)
} }
/* Show BGP peer's information. */ /* 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, static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
afi_t afi, safi_t safi, afi_t afi, safi_t safi,
@ -10945,6 +10927,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
struct peer *peer; struct peer *peer;
int find = 0; int find = 0;
bool nbr_output = false; 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)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) 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; 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) if (use_json)
json_object_boolean_true_add(json, "bgpNoSuchNeighbor"); json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
else else
vty_out(vty, "%% No such neighbor in this view/vrf\n"); 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"); vty_out(vty, "%% No BGP neighbors found\n");
if (use_json) { if (use_json) {
@ -11049,7 +11076,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
: bgp->name); : bgp->name);
} }
if (type == show_peer) { if (type == show_peer || type == show_ipv4_peer ||
type == show_ipv6_peer) {
ret = str2sockunion(ip_str, &su); ret = str2sockunion(ip_str, &su);
if (ret < 0) if (ret < 0)
bgp_show_neighbor(vty, bgp, type, NULL, ip_str, 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, bgp_show_neighbor(vty, bgp, type, &su, NULL,
use_json, json); use_json, json);
} else { } else {
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, bgp_show_neighbor(vty, bgp, type, NULL, NULL,
use_json, json); use_json, json);
} }
json_object_free(json); json_object_free(json);
@ -11151,6 +11179,7 @@ DEFUN (show_ip_bgp_neighbors,
char *vrf = NULL; char *vrf = NULL;
char *sh_arg = NULL; char *sh_arg = NULL;
enum show_type sh_type; enum show_type sh_type;
afi_t afi = AFI_MAX;
bool uj = use_json(argc, argv); bool uj = use_json(argc, argv);
@ -11166,13 +11195,29 @@ DEFUN (show_ip_bgp_neighbors,
vrf = argv[idx + 1]->arg; vrf = argv[idx + 1]->arg;
idx++; 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) if (argv_find(argv, argc, "A.B.C.D", &idx)
|| argv_find(argv, argc, "X:X::X:X", &idx) || argv_find(argv, argc, "X:X::X:X", &idx)
|| argv_find(argv, argc, "WORD", &idx)) { || argv_find(argv, argc, "WORD", &idx)) {
sh_type = show_peer; sh_type = show_peer;
sh_arg = argv[idx]->arg; 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); 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; return CMD_SUCCESS;
} }
static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
safi_t safi, bool use_json) afi_t afi, safi_t safi,
bool use_json, json_object *json)
{ {
struct bgp *bgp; struct bgp *bgp;
struct listnode *node; 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; char *ecom_str;
vpn_policy_direction_t dir; vpn_policy_direction_t dir;
if (use_json) { if (json) {
json_object *json = NULL;
json_object *json_import_vrfs = NULL; json_object *json_import_vrfs = NULL;
json_object *json_export_vrfs = NULL; json_object *json_export_vrfs = NULL;
json = json_object_new_object();
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
if (!bgp) { 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); XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
} }
if (use_json) {
vty_out(vty, "%s\n", vty_out(vty, "%s\n",
json_object_to_json_string_ext(json, json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY)); JSON_C_TO_STRING_PRETTY));
json_object_free(json); json_object_free(json);
}
} else { } else {
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); 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; 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. */ /* "show [ip] bgp route-leak" command. */
DEFUN (show_ip_bgp_route_leak, DEFUN (show_ip_bgp_route_leak,
show_ip_bgp_route_leak_cmd, show_ip_bgp_route_leak_cmd,
@ -11441,6 +11533,7 @@ DEFUN (show_ip_bgp_route_leak,
bool uj = use_json(argc, argv); bool uj = use_json(argc, argv);
int idx = 0; int idx = 0;
json_object *json = NULL;
/* show [ip] bgp */ /* show [ip] bgp */
if (argv_find(argv, argc, "ip", &idx)) { if (argv_find(argv, argc, "ip", &idx)) {
@ -11470,7 +11563,13 @@ DEFUN (show_ip_bgp_route_leak,
return CMD_WARNING; 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, 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; return CMD_SUCCESS;
} }
/* Update redistribute vrf bitmap during triggers like void bgp_redistribute_redo(struct bgp *bgp)
restart networking or delete/add VRFs */ {
void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) 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; int i;
afi_t afi; afi_t afi;
for (afi = AFI_IP; afi < AFI_MAX; afi++) for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if ((old_vrf_id == VRF_UNKNOWN) if (vrf_bitmap_check(zclient->redist[afi][i],
|| vrf_bitmap_check(zclient->redist[afi][i], old_vrf_id))
old_vrf_id)) {
vrf_bitmap_unset(zclient->redist[afi][i], vrf_bitmap_unset(zclient->redist[afi][i],
old_vrf_id); old_vrf_id);
vrf_bitmap_set(zclient->redist[afi][i],
bgp->vrf_id);
}
return; 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_register(struct bgp *);
extern void bgp_zebra_instance_deregister(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, extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t,
unsigned short); unsigned short);
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t, 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; struct peer_af *af;
int afid; int afid;
struct bgp *bgp;
if (!peer) if (!peer)
return NULL; 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) if (afid >= BGP_AF_MAX)
return NULL; return NULL;
bgp = peer->bgp;
assert(peer->peer_af_array[afid] == NULL); assert(peer->peer_af_array[afid] == NULL);
/* Allocate new peer af */ /* 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->safi = safi;
af->afid = afid; af->afid = afid;
af->peer = peer; af->peer = peer;
bgp->af_peer_count[afi][safi]++;
return af; return af;
} }
@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
{ {
struct peer_af *af; struct peer_af *af;
int afid; int afid;
struct bgp *bgp;
if (!peer) if (!peer)
return -1; return -1;
@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
if (!af) if (!af)
return -1; return -1;
bgp = peer->bgp;
bgp_stop_announce_route_timer(af); bgp_stop_announce_route_timer(af);
if (PAF_SUBGRP(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); af->subgroup->id, peer->host);
} }
update_subgroup_remove_peer(af->subgroup, af); 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; peer->peer_af_array[afid] = NULL;
XFREE(MTYPE_BGP_PEER_AF, af); XFREE(MTYPE_BGP_PEER_AF, af);
return 0; return 0;
@ -2714,7 +2723,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
peer->sort = group->conf->sort; peer->sort = group->conf->sort;
} }
if (!group->conf->as) { if (!group->conf->as && peer_sort(peer)) {
if (peer_sort(group->conf) != BGP_PEER_INTERNAL if (peer_sort(group->conf) != BGP_PEER_INTERNAL
&& peer_sort(group->conf) != peer_sort(peer)) { && peer_sort(group->conf) != peer_sort(peer)) {
if (as) if (as)

View File

@ -99,6 +99,9 @@ enum bgp_af_index {
for (afi = AFI_IP; afi < AFI_MAX; afi++) \ for (afi = AFI_IP; afi < AFI_MAX; afi++) \
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) 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_io;
extern struct frr_pthread *bgp_pth_ka; 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_IMPORT (1 << 7)
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8) #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. */ /* Route table for next-hop lookup cache. */
struct bgp_table *nexthop_cache_table[AFI_MAX]; 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; 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 */ /* For benefit of rfapi */
extern struct peer *peer_new(struct bgp *bgp); 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} enable_logfile_mask=${enable_logfile_mask:-0600}
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files]) AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
MPATH_NUM=1 MPATH_NUM=16
case "${enable_multipath}" in case "${enable_multipath}" in
0) 0)

View File

@ -1,9 +1,10 @@
.. _building-centos6:
CentOS 6 CentOS 6
======================================== ========================================
(As an alternative to this installation, you may prefer to create a FRR This document describes installation from source. If you want to build an RPM,
rpm package yourself and install that package instead. See instructions see :ref:`packaging-redhat`.
in redhat/README.rpm\_build.md on how to build a rpm package)
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
@ -24,7 +25,7 @@ CentOS 6 restrictions:
PIMd is needed PIMd is needed
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5 - 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) 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, with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
you can use a newer kernel + headers to get this functionality) 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 - frr\_reload.py will not work, as this requires Python 2.7, and CentOS
@ -235,7 +236,7 @@ settings)::
# Controls source route verification # Controls source route verification
net.ipv4.conf.default.rp_filter = 0 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 .. code-block:: shell

View File

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

View File

@ -11,7 +11,7 @@ FreeBSD 11 restrictions:
Install required packages 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) is first package install and asked)
.. code-block:: shell .. code-block:: shell

View File

@ -11,7 +11,7 @@ FreeBSD 9 restrictions:
Install required packages 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) 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 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 isisd nhrpd ospfd ospf6d pimd ripd ripngd
Enable the serivce Enable the service
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
- ``service frr enable`` - ``service frr enable``

View File

@ -1,35 +1,30 @@
Ubuntu 14.04 LTS Ubuntu 14.04 LTS
=============================================== ================
- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS This document describes installation from source. If you want to build a
requires Linux Kernel 4.5 or higher (LDP can be built, but may have ``deb``, see :ref:`packaging-debian`.
limited use without MPLS) For an updated Ubuntu Kernel, see
http://kernel.ubuntu.com/~kernel-ppa/mainline/
Install required packages Installing Dependencies
------------------------- -----------------------
Add packages: .. code-block:: console
::
apt-get update
apt-get install \ apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo \ git autoconf automake libtool make gawk libreadline-dev texinfo \
dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev python3-sphinx install-info build-essential libc-ares-dev python3-dev python3-sphinx install-info build-essential \
libsnmp-dev perl
.. include:: building-libyang.rst .. 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 Add FRR user and groups
using any packages**
Add frr groups and user
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
:: .. code-block:: console
sudo groupadd -r -g 92 frr sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty sudo groupadd -r -g 85 frrvty
@ -37,60 +32,32 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr --gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty 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 .. include:: include-compile.rst
an example.)
:: Install FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
git clone https://github.com/frrouting/frr.git frr .. code-block:: console
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
Create empty FRR configuration files sudo install -m 775 -o frr -g frr -d /var/log/frr
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
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 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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.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 /dev/null /etc/frr/ospfd.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 /dev/null /etc/frr/ospf6d.conf sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
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 IP & IPv6 forwarding Tweak sysctls
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
other settings) 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):
:: ::
@ -102,37 +69,67 @@ other settings)
# based on Router Advertisements for this host # based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1
**Reboot** or use ``sysctl -p`` to apply the same config to the running Reboot or use ``sysctl -p`` to apply the same config to the running system.
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`:
::
# 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
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.
::
# 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 Install the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
:: .. code-block:: console
sudo install -m 755 tools/frr /etc/init.d/frr 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
Enable daemons Enable daemons
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
those daemons you want to start by systemd. section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
| For example. as required by changing the value to ``yes``.
::
zebra=yes
bgpd=yes
ospfd=yes
ospf6d=yes
ripd=yes
ripngd=yes
isisd=yes
Start the init.d service Start the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
- /etc/init.d/frr start .. code-block:: console
- use ``/etc/init.d/frr status`` to check its status.
/etc/init.d/frr start
Use ``/etc/init.d/frr status`` to check its status.

View File

@ -1,36 +1,30 @@
Ubuntu 16.04 LTS Ubuntu 16.04 LTS
=============================================== ================
- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS This document describes installation from source. If you want to build a
requires Linux Kernel 4.5 or higher (LDP can be built, but may have ``deb``, see :ref:`packaging-debian`.
limited use without MPLS) For an updated Ubuntu Kernel, see
http://kernel.ubuntu.com/~kernel-ppa/mainline/
Install required packages Installing Dependencies
------------------------- -----------------------
Add packages: .. code-block:: console
::
apt-get update
apt-get install \ 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 \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
python3-sphinx install-info build-essential libsystemd-dev install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst .. 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 Add FRR user and groups
using any packages**
Add frr groups and user
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
:: .. code-block:: console
sudo groupadd -r -g 92 frr sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty sudo groupadd -r -g 85 frrvty
@ -38,61 +32,32 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr --gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty 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 .. include:: include-compile.rst
an example.)
:: Install FRR configuration files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
git clone https://github.com/frrouting/frr.git frr .. code-block:: console
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
Create empty FRR configuration files sudo install -m 775 -o frr -g frr -d /var/log/frr
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
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 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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.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 /dev/null /etc/frr/ospfd.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 /dev/null /etc/frr/ospf6d.conf sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
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 Tweak sysctls
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
other settings) 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):
:: ::
@ -104,12 +69,39 @@ other settings)
# based on Router Advertisements for this host # based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1
Enable MPLS Forwarding (with Linux Kernel >= 4.5) Reboot or use ``sysctl -p`` to apply the same config to the running system.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a Add MPLS kernel modules
line equal to ``net.mpls.conf.eth0.input`` or each interface used with """""""""""""""""""""""
MPLS
.. 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
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.
:: ::
@ -119,54 +111,24 @@ MPLS
net.mpls.conf.eth2.input=1 net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000 net.mpls.platform_labels=100000
Add MPLS kernel modules Install service files
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
Add the following lines to ``/etc/modules-load.d/modules.conf``: .. code-block:: console
::
# 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)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons sudo systemctl enable frr
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 daemons Enable daemons
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
those daemons you want to start by systemd. section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
| For example. as required by changing the value to ``yes``.
:: Start FRR
^^^^^^^^^
zebra=yes .. code-block:: console
bgpd=yes
ospfd=yes
ospf6d=yes
ripd=yes
ripngd=yes
isisd=yes
Enable the systemd service systemctl start frr
^^^^^^^^^^^^^^^^^^^^^^^^^^
- systemctl enable frr
Start the systemd service
^^^^^^^^^^^^^^^^^^^^^^^^^
- systemctl start frr
- use ``systemctl status frr`` to check its status.

View File

@ -1,55 +1,44 @@
Ubuntu 18.04 LTS 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 \ sudo apt-get install \
git autoconf automake libtool make gawk libreadline-dev texinfo \ git autoconf automake libtool make gawk libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
python3-sphinx install-info build-essential libsystemd-dev install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst .. include:: building-libyang.rst
Optional packages
^^^^^^^^^^^^^^^^^
Dependencies for additional functionality can be installed as-desired.
Protobuf Protobuf
~~~~~~~~ ^^^^^^^^
:: .. code-block:: console
sudo apt-get install \ sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
protobuf-c-compiler \
libprotobuf-c-dev
ZeroMQ ZeroMQ
~~~~~~ ^^^^^^
:: .. code-block:: console
sudo apt-get install \ sudo apt-get install libzmq5 libzmq3-dev
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 Add FRR user and groups
using any packages**
Add frr groups and user
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
:: .. code-block:: console
sudo groupadd -r -g 92 frr sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty sudo groupadd -r -g 85 frrvty
@ -57,104 +46,29 @@ Add frr groups and user
--gecos "FRR suite" --shell /sbin/nologin frr --gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty 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 Compile
^^^^^^^ ^^^^^^^
:: .. include:: include-compile.rst
make Install FRR configuration files
make check ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sudo make install
Create empty FRR configuration files .. code-block:: console
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Although not strictly necessary, it's good practice to create empty sudo install -m 775 -o frr -g frr -d /var/log/frr
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 frrvty -d /etc/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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.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 /dev/null /etc/frr/ospfd.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 /dev/null /etc/frr/ospf6d.conf sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
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
Monolithic configuration 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,
sudo install -m 755 -o frr -g frr -d /var/log/frr skip the MPLS related configuration in this section.
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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
other settings): other settings):
@ -169,8 +83,10 @@ other settings):
# based on Router Advertisements for this host # based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1
Reboot or use ``sysctl -p`` to apply the same config to the running system.
Add MPLS kernel modules Add MPLS kernel modules
^^^^^^^^^^^^^^^^^^^^^^^ """""""""""""""""""""""
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To 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`: 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_router
mpls_iptunnel 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 Enable MPLS Forwarding
^^^^^^^^^^^^^^^^^^^^^^ """"""""""""""""""""""
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line 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. 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.conf.eth2.input=1
net.mpls.platform_labels=100000 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/frr.service /etc/systemd/system/frr.service
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons sudo systemctl enable frr
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 daemons Enable daemons
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
daemons you want to start by systemd. For example: 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
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
^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: shell .. code-block:: shell
systemctl start frr 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 FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF
<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_. 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 **Option 1: Binary Install**
to the libyang core package in order to build FRR successfully.
The FRR project builds binary ``libyang`` packages, which we offer for download
`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
.. warning:: .. 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: ``libyang`` version 0.16.74 or newer is required to build FRR.
.. 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
.. note:: .. 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 ``libyang`` development packages need to be installed in addition to the
the steps below: 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 cd libyang
git checkout -b tmp origin/tmp
mkdir build; cd build mkdir build; cd build
cmake -DENABLE_LYD_PRIV=ON .. cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
make make
sudo make install sudo make install
When building libyang on CentOS 6, it's also necessary to pass the When building libyang on CentOS 6, it's also necessary to pass the
``-DENABLE_CACHE=OFF`` parameter to cmake. ``-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-centos7
building-frr-for-debian8 building-frr-for-debian8
building-frr-for-debian9 building-frr-for-debian9
building-frr-for-fedora24 building-frr-for-fedora
building-frr-for-freebsd10 building-frr-for-freebsd10
building-frr-for-freebsd11 building-frr-for-freebsd11
building-frr-for-freebsd9 building-frr-for-freebsd9

View File

@ -131,7 +131,7 @@ language = None
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # 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 # The reST default role (used for this markup: `text`) to use for all
# documents. # documents.

View File

@ -6,7 +6,7 @@ Hooks
Libfrr provides type-safe subscribable hook points where other pieces of Libfrr provides type-safe subscribable hook points where other pieces of
code can add one or more callback functions. "type-safe" in this case code can add one or more callback functions. "type-safe" in this case
applies to the function pointers used for subscriptions. The 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. the appropriate function signature (parameters) for the hook.
Example: 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 needs to get the user in the loop—and only these things—are warnings or
errors. 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 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 fixing, for example another router, the system we're running on, or the
configuration. The common point is that the user should probably do configuration. The common point is that the user should probably do

View File

@ -3,7 +3,7 @@
Memtypes 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``. of objects currently allocated, for each of a defined ``MTYPE``.
To this extent, there are *memory groups* and *memory types*. Each memory 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: 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 | | 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 | | MSG\_REPLY | 10 |
+-----------------------------+---------+ +-----------------------------+---------+

View File

@ -31,7 +31,7 @@ Implementation details
Concepts 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: information:
* **Router Information:** flood the Segment Routing capabilities of the node. * **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 Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
* **Extended Prefix:** flood the Prefix 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 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 latter is mandatory for the implementation as it provides the Callback to
Segment Routing functions (see below) when an Extended Link / Prefix or Router 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, (4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
respectively ospf_ext.c. respectively ospf_ext.c.
* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update * 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. 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 * 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 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 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 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 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 is not very helpful 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 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, 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 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 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 `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 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) 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. to modify this TLV is offer by the code.
When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function 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 Like for Router Information, Segment Routing is activate at the Extended
Link/Prefix level with new `segment-routing on` command. This trigger Link/Prefix level with new `segment-routing on` command. This triggers
automtically the flooding of Extended Link LSA for all ospf interface where automatically the flooding of Extended Link LSA for all ospf interfaces where
adjacency is full. For Extended Prefix LSA, the new CLI command adjacency is full. For Extended Prefix LSA, the new CLI command
`segment-routing prefix ...` will trigger the flooding of Prefix SID `segment-routing prefix ...` will trigger the flooding of Prefix SID
TLV/SubTLVs. 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. 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 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 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. the MPLS label prior to sending the packet.
Known limitations Known limitations

View File

@ -1,3 +1,5 @@
.. _packaging-debian:
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 maintainer-release-build
packaging-debian packaging-debian
packaging-redhat

View File

@ -5,13 +5,12 @@
dev_RSTFILES = \ dev_RSTFILES = \
doc/developer/bgp-typecodes.rst \ doc/developer/bgp-typecodes.rst \
doc/developer/bgpd.rst \ doc/developer/bgpd.rst \
doc/developer/building-frr-for-openwrt.rst \
doc/developer/building-frr-for-alpine.rst \ doc/developer/building-frr-for-alpine.rst \
doc/developer/building-frr-for-centos6.rst \ doc/developer/building-frr-for-centos6.rst \
doc/developer/building-frr-for-centos7.rst \ doc/developer/building-frr-for-centos7.rst \
doc/developer/building-frr-for-debian8.rst \ doc/developer/building-frr-for-debian8.rst \
doc/developer/building-frr-for-debian9.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-freebsd10.rst \
doc/developer/building-frr-for-freebsd11.rst \ doc/developer/building-frr-for-freebsd11.rst \
doc/developer/building-frr-for-freebsd9.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-netbsd7.rst \
doc/developer/building-frr-for-omnios.rst \ doc/developer/building-frr-for-omnios.rst \
doc/developer/building-frr-for-openbsd6.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-ubuntu1404.rst \
doc/developer/building-frr-for-ubuntu1604.rst \ doc/developer/building-frr-for-ubuntu1604.rst \
doc/developer/building-frr-for-ubuntu1804.rst \ doc/developer/building-frr-for-ubuntu1804.rst \
@ -27,6 +27,7 @@ dev_RSTFILES = \
doc/developer/cli.rst \ doc/developer/cli.rst \
doc/developer/conf.py \ doc/developer/conf.py \
doc/developer/hooks.rst \ doc/developer/hooks.rst \
doc/developer/include-compile.rst \
doc/developer/index.rst \ doc/developer/index.rst \
doc/developer/library.rst \ doc/developer/library.rst \
doc/developer/logging.rst \ doc/developer/logging.rst \
@ -37,8 +38,9 @@ dev_RSTFILES = \
doc/developer/ospf-api.rst \ doc/developer/ospf-api.rst \
doc/developer/ospf-sr.rst \ doc/developer/ospf-sr.rst \
doc/developer/ospf.rst \ doc/developer/ospf.rst \
doc/developer/packaging.rst \
doc/developer/packaging-debian.rst \ doc/developer/packaging-debian.rst \
doc/developer/packaging-redhat.rst
doc/developer/packaging.rst \
doc/developer/testing.rst \ doc/developer/testing.rst \
doc/developer/topotests-snippets.rst \ doc/developer/topotests-snippets.rst \
doc/developer/topotests.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 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. there are different ways to do so.
Notes: 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 (`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 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. to spawn commands.
Interacting with the Linux sandbox Interacting with the Linux sandbox
@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures:
.. note:: .. 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 Invoking mininet CLI
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
@ -195,7 +195,7 @@ Loading JSON from a file:
Comparing JSON output 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: it to assert a minimalist schema:
.. code:: py .. code:: py

View File

@ -151,7 +151,7 @@ Collect Memory Leak Information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FRR processes have the capabilities to report remaining memory allocations upon 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.:: ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" 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 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 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 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 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 :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 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 codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH`` 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 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 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 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 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: message from VTYSH to a daemon:
:: ::
@ -178,7 +178,7 @@ message from VTYSH to a daemon:
00000010: 6c0a 00 l.. 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 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 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 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, ``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
bugfix releases may occur sooner. bugfix releases may occur sooner.
Bugfixes are applied to the two most recent releases. Security fixes are Bugfixes are applied to the two most recent releases. However, backporting of bug
backported to all releases less than or equal to at least one year old. Security fixes to older than the two most recent releases will not be prevented, if acked
fixes may also be backported to older releases depending on severity. 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 ) Long term support branches ( LTS )
----------------------------------------- -----------------------------------------
@ -371,7 +376,7 @@ system in which submissions from an individual representing one company should
be merged by someone unaffiliated with that company. be merged by someone unaffiliated with that company.
Guidelines for code review Guidelines for code review
"""""""""""""""""""""""""" --------------------------
- As a rule of thumb, the depth of the review should be proportional to the - As a rule of thumb, the depth of the review should be proportional to the
scope and / or impact of the patch. 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 # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # 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 # The reST default role (used for this markup: `text`) to use for all
# documents. # 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| 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] .. |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... .. index:: find COMMAND...
.. clicmd:: 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 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: 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 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 problematic in non-full-mesh iBGP topologies that further reduce the routing
information known to each speaker. This has primarily been documented with iBGP information known to each speaker. This has primarily been documented with iBGP
route-reflection topologies. However, any route-hiding technologies potentially :ref:`route-reflection <bgp-route-reflector>` topologies. However, any
could also exacerbate oscillation with MED. route-hiding technologies potentially could also exacerbate oscillation with MED.
This second issue occurs where speakers each have only a subset of routes, and 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 - 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`` represents well-known communities value
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements ``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
the purpose Graceful BGP Session Shutdown to reduce the amount of 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 of the community needs to be supported from your peers side to
actually have any effect. 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``
``llgr-stale`` represents well-known communities value ``LLGR_STALE`` ``llgr-stale`` represents well-known communities value ``LLGR_STALE``
``0xFFFF0006`` ``65535:6``. ``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 Long-lived Graceful Restart Capability as described in
[Draft-IETF-uttaro-idr-bgp-persistence]_. [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 implementation) choose allow to reject or modify routes on the
presence or absence of this community. presence or absence of this community.
``no-llgr`` ``no-llgr``
``no-llgr`` represents well-known communities value ``NO_LLGR`` ``no-llgr`` represents well-known communities value ``NO_LLGR``
``0xFFFF0007`` ``65535:7``. ``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 Long-lived Graceful Restart Capability as described in
[Draft-IETF-uttaro-idr-bgp-persistence]_. [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 implementation) choose allow to reject or modify routes on the
presence or absence of this community. presence or absence of this community.
@ -1251,7 +1251,7 @@ UPDATE messages.
There are two types of community list: There are two types of community list:
standard standard
This type accepts an explicit value for the atttribute. This type accepts an explicit value for the attribute.
expanded expanded
This type accepts a regular expression. Because the regex must be This type accepts a regular expression. Because the regex must be
@ -2240,10 +2240,15 @@ Displaying Routes by AS Path
Route Reflector 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 When route reflectors are configured, these will reflect the routes announced
.. clicmd:: bgp cluster-id A.B.C.D by the peers configured as clients. A route reflector client is configured
with:
.. index:: neighbor PEER route-reflector-client .. index:: neighbor PEER route-reflector-client
.. clicmd:: neighbor PEER route-reflector-client .. clicmd:: neighbor PEER route-reflector-client
@ -2251,6 +2256,13 @@ Route Reflector
.. index:: no neighbor PEER route-reflector-client .. index:: no neighbor PEER route-reflector-client
.. clicmd:: 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: .. _routing-policy:
@ -2469,7 +2481,7 @@ certainly contains silly mistakes, if not serious flaws.
route-map rm-no-export permit 20 route-map rm-no-export permit 20
! !
route-map rm-blackhole permit 10 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 ip next-hop 127.0.0.1
set local-preference 10 set local-preference 10
set community additive no-export 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 depicts how Route Targets are configured and how VRFs and cross VRF
configuration is done. Note that the VRF are mapped on Linux Network configuration is done. Note that the VRF are mapped on Linux Network
Namespaces. For data traffic to cross VRF boundaries, virtual ethernet 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 .. code-block:: frr
@ -322,7 +322,7 @@ There are some other known issues:
- The validation procedure depicted in :rfc:`5575` is not available. - The validation procedure depicted in :rfc:`5575` is not available.
This validation procedure has not been implemented, as this feature was not 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. - 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 .. option:: --enable-multipath=X
Compile FRR with up to X way ECMP supported. This number can be from 0-999. 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 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 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 .. 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 SPF-triggering event occurs within the hold-time of the previous SPF
calculation. calculation.
This command supercedes the *timers spf* command in previous FRR This command supersedes the *timers spf* command in previous FRR
releases. releases.
.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400) .. 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 When a incoming packet matches the destination prefix specified, take the
packet and forward according to the nexthops specified. This command accepts 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:`match src-ip PREFIX` command for matching.
.. clicmd:: set nexthop-group NAME .. 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. Set the IGMP version used on this interface. The default value is 3.
.. index:: ip multicat boundary oil WORD .. index:: ip multicast boundary oil WORD
.. clicmd:: ip multicat boundary oil WORD .. clicmd:: ip multicast boundary oil WORD
Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join 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 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 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. keyword. At present, no sharp commands will be preserved in the config.
.. index:: sharp install .. 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 statistics information matches the same file statistics information as
`/proc/self/ns/net` ( through stat() function). As statistics information `/proc/self/ns/net` ( through stat() function). As statistics information
matches, then `vrf0` stands for the new default namespace name. 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`. namespace name `vrf0`.
For those who don't use VRF backend with *Linux network namespace*, it is 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 .. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
.. clicmd:: [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. route entry.
GATEWAY is the gateway IP address to reach, in order to reach the prefix. GATEWAY is the gateway IP address to reach, in order to reach the prefix.
INTERFACE is the interface behind which the prefix is located. INTERFACE is the interface behind which the prefix is located.

View File

@ -1,35 +1,58 @@
FROM alpine:3.7 as source-builder # This stage builds a dist tarball from the source
ARG commit FROM alpine:edge as source-builder
RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \
binutils binutils-libs bison bsd-compat-headers build-base \ RUN mkdir -p /src/alpine
c-ares c-ares-dev ca-certificates cryptsetup-libs curl \ COPY alpine/APKBUILD.in /src/alpine
device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \ RUN source /src/alpine/APKBUILD.in \
git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \ && echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \ && apk add \
libgomp libisoburn libisofs libltdl libressl libssh2 \ --no-cache \
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \ --update-cache \
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \ $makedepends \
patch pax-utils pcre perl pkgconf python2 python2-dev readline \ gzip
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \
groff gzip bc py-sphinx COPY . /src
ADD . /src ARG PKGVER
RUN (cd /src && \ RUN cd /src \
./bootstrap.sh && \ && ./bootstrap.sh \
./configure \ && ./configure \
--enable-numeric-version \ --enable-numeric-version \
--with-pkg-extra-version=_git$commit && \ --with-pkg-extra-version="_git$PKGVER" \
make dist) && make dist
FROM alpine:3.7 as alpine-builder
RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk # This stage builds an apk from the dist tarball
ADD docker/alpine/alpine-build.sh /usr/bin/ FROM alpine:edge as alpine-builder
ADD docker/alpine/builder /etc/sudoers.d # Don't use nocache here so that abuild can use the cache
COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/ 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 RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
USER builder USER builder
RUN /usr/bin/alpine-build.sh RUN cd /dist \
FROM alpine:3.7 && 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 RUN mkdir -p /pkgs/apk
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/ COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
RUN apk add --no-cache tini RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk && 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" ] 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 #!/bin/sh
set -e set -e
set -v
set -x set -x
## ##
# commit must be converted to decimal # Package version needs to be decimal
## ##
c=`git rev-parse --short=10 HEAD` GITREV="$(git rev-parse --short=10 HEAD)"
commit=`printf '%u\n' 0x$c` PKGVER="$(printf '%u\n' 0x$GITREV)"
docker build -f docker/alpine/Dockerfile \
--build-arg commit=$commit -t frr:alpine-$c . docker build \
id=`docker create frr:alpine-$c` --pull \
docker cp ${id}:/pkgs/ docker --file=docker/alpine/Dockerfile \
docker rm $id --build-arg="PKGVER=$PKGVER" \
docker rmi frr:alpine-$c --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... # For volume mounts...
## ##
chown -R frr:frr /etc/frr chown -R frr:frr /etc/frr
/etc/init.d/frr start /usr/lib/frr/frrinit.sh start
exec sleep 10000d
# 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) if (prefix->rij->count)
return EIGRP_FSM_KEEP_STATE; return EIGRP_FSM_KEEP_STATE;
zlog_info("All reply received\n"); zlog_info("All reply received");
if (head->reported_distance < prefix->fdistance) { if (head->reported_distance < prefix->fdistance) {
return EIGRP_FSM_EVENT_LR_FCS; 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) { } else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE; return EIGRP_FSM_KEEP_STATE;
} else { } else {
zlog_info("All reply received\n"); zlog_info("All reply received");
return EIGRP_FSM_EVENT_LR; return EIGRP_FSM_EVENT_LR;
} }
} else if (msg->packet_type == EIGRP_OPC_UPDATE } 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) { if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE; return EIGRP_FSM_KEEP_STATE;
} else { } else {
zlog_info("All reply received\n"); zlog_info("All reply received");
if (head->reported_distance if (head->reported_distance
< prefix->fdistance) { < prefix->fdistance) {
return EIGRP_FSM_EVENT_LR_FCS; 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) { } else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE; return EIGRP_FSM_KEEP_STATE;
} else { } else {
zlog_info("All reply received\n"); zlog_info("All reply received");
return EIGRP_FSM_EVENT_LR; return EIGRP_FSM_EVENT_LR;
} }
} else if (msg->packet_type == EIGRP_OPC_UPDATE } 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) {
if (tw_adj->state > ISIS_THREEWAY_DOWN) { if (tw_adj->state > ISIS_THREEWAY_DOWN) {
if (isis->debugs & DEBUG_ADJ_PACKETS) { 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->area->area_tag,
iih->circuit->interface->name, iih->circuit->interface->name,
tw_adj->state); 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)) { || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
if (isis->debugs & DEBUG_ADJ_PACKETS) { 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->area->area_tag,
iih->circuit->interface->name); 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) 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; retval = ISIS_OK;
out: 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) if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1; 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 * Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back * 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; struct interface *ifp;
switch (vrf_get_backend()) { switch (vrf_get_backend()) {
case VRF_BACKEND_UNKNOWN:
case VRF_BACKEND_NETNS: case VRF_BACKEND_NETNS:
ifp = if_lookup_by_name(name, vrf_id); ifp = if_lookup_by_name(name, vrf_id);
if (ifp) if (ifp)
@ -1279,6 +1280,11 @@ static int lib_interface_create(enum nb_event event,
vrf->name); vrf->name);
return NB_ERR_VALIDATION; 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) { if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
ifp = if_lookup_by_name_all_vrf(ifname); ifp = if_lookup_by_name_all_vrf(ifname);
if (ifp && ifp->vrf_id != vrf->vrf_id) { 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_DELETE),
DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE), DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
DESC_ENTRY(ZEBRA_HELLO), DESC_ENTRY(ZEBRA_HELLO),
DESC_ENTRY(ZEBRA_CAPABILITIES),
DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER), DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER), DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE), 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_VRF_LABEL),
DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE), DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER), DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER),
DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV), DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV), DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB), 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_LABEL_MANAGER_CONNECT_ASYNC),
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_RELEASE_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_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP), 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_DESTROY),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD), DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE), 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), DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
}; };
#undef DESC_ENTRY #undef DESC_ENTRY

View File

@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b)
return strcmp(a, 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) static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
{ {
int ret; int ret;
ret = sockunion_cmp(&nh1->addr, &nh2->addr); ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
if (ret) if (ret)
return ret; return ret;
@ -209,6 +223,9 @@ static void nhgl_delete(struct nexthop_hold *nh)
XFREE(MTYPE_TMP, nh->nhvrf_name); XFREE(MTYPE_TMP, nh->nhvrf_name);
if (nh->addr)
sockunion_free(nh->addr);
XFREE(MTYPE_TMP, nh); 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); nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
if (intf) if (intf)
nh->intf = XSTRDUP(MTYPE_TMP, intf); nh->intf = XSTRDUP(MTYPE_TMP, intf);
if (addr)
nh->addr = *addr; nh->addr = sockunion_dup(addr);
listnode_add_sort(nhgc->nhg_list, nh); 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)) { for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 && 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) nhgc_cmp_helper(intf, nh->intf) == 0)
break; break;
} }
@ -320,13 +337,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
return; return;
list_delete_node(nhgc->nhg_list, node); list_delete_node(nhgc->nhg_list, node);
nhgl_delete(nh);
if (nh->nhvrf_name)
XFREE(MTYPE_TMP, nh->nhvrf_name);
if (nh->intf)
XFREE(MTYPE_TMP, nh->intf);
XFREE(MTYPE_TMP, nh);
} }
static bool nexthop_group_parse_nexthop(struct nexthop *nhop, 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; nhop->vrf_id = vrf->vrf_id;
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) { if (addr->sa.sa_family == AF_INET) {
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf) { if (intf)
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); else
if (nhop->ifindex == IFINDEX_INTERNAL)
return false;
} else
nhop->type = NEXTHOP_TYPE_IPV4; nhop->type = NEXTHOP_TYPE_IPV4;
} else { } else {
memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16); nhop->gate.ipv6 = addr->sin6.sin6_addr;
if (intf) { if (intf)
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); else
if (nhop->ifindex == IFINDEX_INTERNAL)
return false;
} else
nhop->type = NEXTHOP_TYPE_IPV6; nhop->type = NEXTHOP_TYPE_IPV6;
} }
} else
nhop->type = NEXTHOP_TYPE_IFINDEX;
return true; return true;
} }
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, 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 NO_STR
"Specify one of the nexthops in this ECMP group\n" "Specify one of the nexthops in this ECMP group\n"
"v4 Address\n" "v4 Address\n"
"v6 Address\n" "v6 Address\n"
"Interface to use\n" "Interface to use\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n" "If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n") "The nexthop-vrf Name\n")
{ {
@ -385,13 +405,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
struct nexthop *nh; struct nexthop *nh;
bool legal; 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); legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
if (nhop.type == NEXTHOP_TYPE_IPV6 if (nhop.type == NEXTHOP_TYPE_IPV6
@ -482,7 +495,8 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
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) if (nh->intf)
vty_out(vty, " %s", nh->intf); vty_out(vty, " %s", nh->intf);
@ -526,7 +540,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
struct nexthop nhop; struct nexthop nhop;
struct nexthop *nh; struct nexthop *nh;
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr, if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
nhh->intf, nhh->intf,
nhh->nhvrf_name)) nhh->nhvrf_name))
continue; continue;
@ -562,7 +576,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
struct nexthop nhop; struct nexthop nhop;
struct nexthop *nh; struct nexthop *nh;
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr, if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
nhh->intf, nhh->intf,
nhh->nhvrf_name)) nhh->nhvrf_name))
continue; continue;
@ -600,7 +614,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
struct nexthop nhop; struct nexthop nhop;
if (!nexthop_group_parse_nexthop( if (!nexthop_group_parse_nexthop(
&nhop, &nhh->addr, nhh->intf, &nhop, nhh->addr, nhh->intf,
nhh->nhvrf_name)) nhh->nhvrf_name))
continue; continue;

View File

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

View File

@ -348,41 +348,60 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
* configurations. Given a new subtree, calculate all new YANG data nodes, * configurations. Given a new subtree, calculate all new YANG data nodes,
* excluding default leafs and leaf-lists. This is a recursive function. * excluding default leafs and leaf-lists. This is a recursive function.
*/ */
static void nb_config_diff_new_subtree(const struct lyd_node *dnode, static void nb_config_diff_created(const struct lyd_node *dnode,
struct nb_config_cbs *changes) struct nb_config_cbs *changes)
{ {
enum nb_operation operation;
struct lyd_node *child; struct lyd_node *child;
LY_TREE_FOR (dnode->child, child) { switch (dnode->schema->nodetype) {
enum nb_operation operation;
switch (child->schema->nodetype) {
case LYS_LEAF: case LYS_LEAF:
case LYS_LEAFLIST: case LYS_LEAFLIST:
if (lyd_wd_default((struct lyd_node_leaf_list *)child)) if (lyd_wd_default((struct lyd_node_leaf_list *)dnode))
break; break;
if (nb_operation_is_valid(NB_OP_CREATE, child->schema)) if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
operation = NB_OP_CREATE; operation = NB_OP_CREATE;
else if (nb_operation_is_valid(NB_OP_MODIFY, else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
child->schema))
operation = NB_OP_MODIFY; operation = NB_OP_MODIFY;
else else
continue; return;
nb_config_diff_add_change(changes, operation, child); nb_config_diff_add_change(changes, operation, dnode);
break; break;
case LYS_CONTAINER: case LYS_CONTAINER:
case LYS_LIST: case LYS_LIST:
if (nb_operation_is_valid(NB_OP_CREATE, child->schema)) if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
nb_config_diff_add_change(changes, NB_OP_CREATE, nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
child);
nb_config_diff_new_subtree(child, changes); /* Process child nodes recursively. */
LY_TREE_FOR (dnode->child, child) {
nb_config_diff_created(child, changes);
}
break; break;
default: default:
break; 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);
}
}
} }
/* Calculate the delta between two different configurations. */ /* Calculate the delta between two different configurations. */
@ -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++) { for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
LYD_DIFFTYPE type; LYD_DIFFTYPE type;
struct lyd_node *dnode; struct lyd_node *dnode;
enum nb_operation operation;
type = diff->type[i]; type = diff->type[i];
switch (type) { switch (type) {
case LYD_DIFF_CREATED: case LYD_DIFF_CREATED:
dnode = diff->second[i]; dnode = diff->second[i];
nb_config_diff_created(dnode, changes);
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;
break; break;
case LYD_DIFF_DELETED: case LYD_DIFF_DELETED:
dnode = diff->first[i]; dnode = diff->first[i];
operation = NB_OP_DESTROY; nb_config_diff_deleted(dnode, changes);
break; break;
case LYD_DIFF_CHANGED: case LYD_DIFF_CHANGED:
dnode = diff->second[i]; dnode = diff->second[i];
operation = NB_OP_MODIFY; nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
break; break;
case LYD_DIFF_MOVEDAFTER1: case LYD_DIFF_MOVEDAFTER1:
case LYD_DIFF_MOVEDAFTER2: case LYD_DIFF_MOVEDAFTER2:
default: default:
continue; 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); lyd_free_diff(diff);

View File

@ -708,12 +708,8 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
/* If we're already elevated, just return */ /* If we're already elevated, just return */
pthread_mutex_lock(&(privs->mutex)); pthread_mutex_lock(&(privs->mutex));
if (++privs->refcount > 1) { {
pthread_mutex_unlock(&(privs->mutex)); if (++(privs->refcount) == 1) {
return privs;
}
pthread_mutex_unlock(&(privs->mutex));
errno = 0; errno = 0;
if (privs->change(ZPRIVS_RAISE)) { if (privs->change(ZPRIVS_RAISE)) {
zlog_err("%s: Failed to raise privileges (%s)", zlog_err("%s: Failed to raise privileges (%s)",
@ -721,6 +717,10 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
} }
errno = save_errno; errno = save_errno;
privs->raised_in_funcname = funcname; privs->raised_in_funcname = funcname;
}
}
pthread_mutex_unlock(&(privs->mutex));
return privs; return privs;
} }
@ -733,19 +733,20 @@ void _zprivs_lower(struct zebra_privs_t **privs)
/* Don't lower privs if there's another caller */ /* Don't lower privs if there's another caller */
pthread_mutex_lock(&(*privs)->mutex); pthread_mutex_lock(&(*privs)->mutex);
if (--((*privs)->refcount) > 0) { {
pthread_mutex_unlock(&(*privs)->mutex); if (--((*privs)->refcount) == 0) {
return;
}
pthread_mutex_unlock(&(*privs)->mutex);
errno = 0; errno = 0;
if ((*privs)->change(ZPRIVS_LOWER)) { if ((*privs)->change(ZPRIVS_LOWER)) {
zlog_err("%s: Failed to lower privileges (%s)", zlog_err("%s: Failed to lower privileges (%s)",
(*privs)->raised_in_funcname, safe_strerror(errno)); (*privs)->raised_in_funcname,
safe_strerror(errno));
} }
errno = save_errno; errno = save_errno;
(*privs)->raised_in_funcname = NULL; (*privs)->raised_in_funcname = NULL;
}
}
pthread_mutex_unlock(&(*privs)->mutex);
*privs = 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); struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
static int vrf_backend; static int vrf_backend;
static int vrf_backend_configured;
static struct zebra_privs_t *vrf_daemon_privs; static struct zebra_privs_t *vrf_daemon_privs;
static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL; 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) int vrf_get_backend(void)
{ {
if (!vrf_backend_configured)
return VRF_BACKEND_UNKNOWN;
return vrf_backend; return vrf_backend;
} }
void vrf_configure_backend(int vrf_backend_netns) void vrf_configure_backend(int vrf_backend_netns)
{ {
vrf_backend = vrf_backend_netns; vrf_backend = vrf_backend_netns;
vrf_backend_configured = 1;
} }
int vrf_handler_create(struct vty *vty, const char *vrfname, 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 %u is already configured with VRF %s\n",
vrf->vrf_id, vrf->name); vrf->vrf_id, vrf->name);
else 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); vrf->vrf_id, vrf->name);
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }

View File

@ -103,6 +103,7 @@ DECLARE_QOBJ_TYPE(vrf)
/* Allow VRF with netns as backend */ /* Allow VRF with netns as backend */
#define VRF_BACKEND_VRF_LITE 0 #define VRF_BACKEND_VRF_LITE 0
#define VRF_BACKEND_NETNS 1 #define VRF_BACKEND_NETNS 1
#define VRF_BACKEND_UNKNOWN 2
extern struct vrf_id_head vrfs_by_id; extern struct vrf_id_head vrfs_by_id;
extern struct vrf_name_head vrfs_by_name; 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) if (zclient_debug)
zlog_debug("zclient_start is called"); zlog_debug("scheduling zclient connection");
zclient_event(ZCLIENT_SCHEDULE, zclient); zclient_event(ZCLIENT_SCHEDULE, zclient);
} }
@ -2504,8 +2504,9 @@ static int zclient_read(struct thread *thread)
length -= ZEBRA_HEADER_SIZE; length -= ZEBRA_HEADER_SIZE;
if (zclient_debug) if (zclient_debug)
zlog_debug("zclient 0x%p command 0x%x VRF %u\n", zlog_debug("zclient 0x%p command %s VRF %u",
(void *)zclient, command, vrf_id); (void *)zclient, zserv_command_string(command),
vrf_id);
switch (command) { switch (command) {
case ZEBRA_CAPABILITIES: case ZEBRA_CAPABILITIES:
@ -2574,14 +2575,14 @@ static int zclient_read(struct thread *thread)
break; break;
case ZEBRA_NEXTHOP_UPDATE: case ZEBRA_NEXTHOP_UPDATE:
if (zclient_debug) if (zclient_debug)
zlog_debug("zclient rcvd nexthop update\n"); zlog_debug("zclient rcvd nexthop update");
if (zclient->nexthop_update) if (zclient->nexthop_update)
(*zclient->nexthop_update)(command, zclient, length, (*zclient->nexthop_update)(command, zclient, length,
vrf_id); vrf_id);
break; break;
case ZEBRA_IMPORT_CHECK_UPDATE: case ZEBRA_IMPORT_CHECK_UPDATE:
if (zclient_debug) if (zclient_debug)
zlog_debug("zclient rcvd import check update\n"); zlog_debug("zclient rcvd import check update");
if (zclient->import_check_update) if (zclient->import_check_update)
(*zclient->import_check_update)(command, zclient, (*zclient->import_check_update)(command, zclient,
length, vrf_id); length, vrf_id);
@ -2608,7 +2609,7 @@ static int zclient_read(struct thread *thread)
break; break;
case ZEBRA_FEC_UPDATE: case ZEBRA_FEC_UPDATE:
if (zclient_debug) if (zclient_debug)
zlog_debug("zclient rcvd fec update\n"); zlog_debug("zclient rcvd fec update");
if (zclient->fec_update) if (zclient->fec_update)
(*zclient->fec_update)(command, zclient, length); (*zclient->fec_update)(command, zclient, length);
break; break;

View File

@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area)
if (IS_AREA_STUB(area)) { if (IS_AREA_STUB(area)) {
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) 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); OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
} else if (IS_AREA_ENABLED(area)) { } else if (IS_AREA_ENABLED(area)) {
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) 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_OPT_SET(area->options, OSPF6_OPT_E);
ospf6_asbr_send_externals_to_area(area); ospf6_asbr_send_externals_to_area(area);
} }
@ -450,7 +450,7 @@ DEFUN (area_range,
range->path.u.cost_config = cost; 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); argv[idx_ipv6_prefixlen]->arg, range->flag);
if (range->rnode == NULL) { if (range->rnode == NULL) {
ospf6_route_add(range, oa->range_table); 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)) { for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) { 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); __func__, lsa->name);
ospf6_flood_area(NULL, lsa, oa); 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); lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
if (lsa == NULL) { if (lsa == NULL) {
if (IS_OSPF6_DEBUG_SPF(PROCESS)) 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); oa->name);
return; 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)) if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0; return 0;
if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
return 0;
ifindex = api.nexthops[0].ifindex; ifindex = api.nexthops[0].ifindex;
nexthop = &api.nexthops[0].gate.ipv6; 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; olsa = (struct opaque_lsa *)data;
opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE; 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++) { for (i = 0; i < opaquelen; i++) {
zlog_debug("0x%x ", olsa->mydata[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) void msg_print(struct msg *msg)
{ {
if (!msg) { if (!msg) {
zlog_debug("msg_print msg=NULL!\n"); zlog_debug("msg_print msg=NULL!");
return; return;
} }

View File

@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp)
/* zlog_warn for debugging */ /* zlog_warn for debugging */
zlog_warn("ospf_apiserver_del_if"); 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); ifp->ifindex);
oi = ospf_apiserver_if_lookup_by_ifp(ifp); 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++) { for (i = 0; i < opaquelen; i++) {
zlog_debug("0x%x ", olsa->data[i]); zlog_debug("0x%x ", olsa->data[i]);
} }
zlog_debug("\n");
} }
return; return;
} }

View File

@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length,
oi = nbr->oi; 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)) if (*length + delta > ospf_packet_max(oi))
return 0; return 0;
@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s)
{ {
struct ospf_lsa *lsa; struct ospf_lsa *lsa;
uint16_t length = OSPF_LS_REQ_MIN_SIZE; 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_table *table;
struct route_node *rn; struct route_node *rn;
int i; int i;
@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
assert(lsa->data); assert(lsa->data);
/* Will it fit? */ /* Will it fit? Minimum it has to fit atleast one */
if (length + delta + ntohs(lsa->data->length) > size_noauth) if ((length + delta + ntohs(lsa->data->length) > size_noauth) &&
(count > 0))
break; break;
/* Keep pointer to LS age. */ /* 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; struct listnode *node, *nnode;
uint16_t length = OSPF_LS_ACK_MIN_SIZE; 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; struct ospf_lsa *lsa;
for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
assert(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; break;
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); 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 { else {
zlog_debug(" Segment Routing Algorithm TLV:\n"); zlog_debug(" Segment Routing Algorithm TLV:");
for (i = 0; i < ntohs(algo->header.length); i++) for (i = 0; i < ntohs(algo->header.length); i++)
switch (algo->value[i]) { switch (algo->value[i]) {
case 0: case 0:
zlog_debug(" Algorithm %d: SPF\n", i); zlog_debug(" Algorithm %d: SPF", i);
break; break;
case 1: case 1:
zlog_debug(" Algorithm %d: Strict SPF\n", i); zlog_debug(" Algorithm %d: Strict SPF", i);
break; break;
default: default:
zlog_debug( 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 /* Sanity check, if LSA type unknwon
merley skip any LSA */ merley skip any LSA */
if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_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; return NULL;
} }

View File

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

View File

@ -1600,7 +1600,7 @@ static int ospf_sr_update_schedule(struct thread *t)
monotime(&stop_time); monotime(&stop_time);
if (IS_DEBUG_OSPF_SR) 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__, __func__,
(stop_time.tv_sec - start_time.tv_sec) * 1000000LL (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+ (stop_time.tv_usec - start_time.tv_usec)); + (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 if (ospf->stub_router_startup_time
!= OSPF_STUB_ROUTER_UNCONFIGURED) != OSPF_STUB_ROUTER_UNCONFIGURED)
json_object_int_add( json_object_int_add(
json_vrf, "postStartEnabledMsecs", json_vrf, "postStartEnabledSecs",
ospf->stub_router_startup_time / 1000); ospf->stub_router_startup_time);
if (ospf->stub_router_shutdown_time if (ospf->stub_router_shutdown_time
!= OSPF_STUB_ROUTER_UNCONFIGURED) != OSPF_STUB_ROUTER_UNCONFIGURED)
json_object_int_add( json_object_int_add(
json_vrf, "preShutdownEnabledMsecs", json_vrf, "preShutdownEnabledSecs",
ospf->stub_router_shutdown_time / 1000); ospf->stub_router_shutdown_time);
} else { } else {
vty_out(vty, vty_out(vty,
" Stub router advertisement is configured\n"); " 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", json_object_int_add(json_interface_sub, "cost",
oi->output_cost); oi->output_cost);
json_object_int_add( json_object_int_add(
json_interface_sub, "transmitDelayMsecs", json_interface_sub, "transmitDelaySecs",
1000 / OSPF_IF_PARAM(oi, transmit_delay)); OSPF_IF_PARAM(oi, transmit_delay));
json_object_string_add(json_interface_sub, "state", json_object_string_add(json_interface_sub, "state",
lookup_msg(ospf_ism_state_msg, lookup_msg(ospf_ism_state_msg,
oi->state, NULL)); 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) if (OSPF_IF_PARAM(oi, fast_hello) == 0)
json_object_int_add( json_object_int_add(
json_interface_sub, "timerMsecs", json_interface_sub, "timerMsecs",
1000 / OSPF_IF_PARAM(oi, v_hello)); OSPF_IF_PARAM(oi, v_hello) * 1000);
else else
json_object_int_add( json_object_int_add(
json_interface_sub, "timerMsecs", json_interface_sub, "timerMsecs",
1000 / OSPF_IF_PARAM(oi, fast_hello)); 1000 / OSPF_IF_PARAM(oi, fast_hello));
json_object_int_add(json_interface_sub, json_object_int_add(json_interface_sub,
"timerDeadMsecs", "timerDeadSecs",
1000 / OSPF_IF_PARAM(oi, v_wait)); OSPF_IF_PARAM(oi, v_wait));
json_object_int_add(json_interface_sub, json_object_int_add(json_interface_sub,
"timerWaitMsecs", "timerWaitSecs",
1000 / OSPF_IF_PARAM(oi, v_wait)); OSPF_IF_PARAM(oi, v_wait));
json_object_int_add( json_object_int_add(
json_interface_sub, "timerRetransmit", json_interface_sub, "timerRetransmitSecs",
1000 / OSPF_IF_PARAM(oi, retransmit_interval)); OSPF_IF_PARAM(oi, retransmit_interval));
} else { } else {
vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Timer intervals configured,");
vty_out(vty, " Hello "); 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 static void
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg, struct nexthop_group nhg,
enum nexthop_types_t nh_afi); enum nexthop_types_t nh_type);
/* /*
* Nexthop refcount. * Nexthop refcount.
@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
switch (pbrnc1->nexthop->type) { switch (pbrnc1->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
return true; return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4:
return pbrnc1->nexthop->gate.ipv4.s_addr 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_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(nhgc->name); 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, 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_group_cache *pnhgc;
struct pbr_nexthop_cache pnhc_find = {}; struct pbr_nexthop_cache pnhc_find = {};
struct pbr_nexthop_cache *pnhc; 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 */ /* find pnhgc by name */
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.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) if (pnhgc->nhh->count)
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
else 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); pbr_map_check_nh_group_change(nhgc->name);
} }
@ -372,22 +380,32 @@ void pbr_nht_route_removed_for_table(uint32_t table_id)
* - AFI_MAX on error * - AFI_MAX on error
*/ */
static afi_t pbr_nht_which_afi(struct nexthop_group nhg, 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; struct nexthop *nexthop;
afi_t install_afi = AFI_MAX; afi_t install_afi = AFI_MAX;
bool v6, v4, bh; 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; v6 = v4 = bh = false;
if (!nh_afi) {
for (ALL_NEXTHOPS(nhg, nexthop)) { for (ALL_NEXTHOPS(nhg, nexthop)) {
nh_afi = nexthop->type; nh_type = nexthop->type;
break;
}
}
switch (nh_afi) { switch (nh_type) {
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
break; break;
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4:
@ -402,9 +420,13 @@ static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
break; break;
case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_BLACKHOLE:
bh = true; bh = true;
install_afi = AFI_MAX;
break; break;
} }
}
/* Interface and/or blackhole nexthops only. */
if (!v4 && !v6)
install_afi = AFI_MAX;
if (!bh && v6 && v4) if (!bh && v6 && v4)
DEBUGD(&pbr_dbg_nht, 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) struct nexthop_group nhg)
{ {
afi_t install_afi; 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); 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 static void
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg, struct nexthop_group nhg,
enum nexthop_types_t nh_afi) enum nexthop_types_t nh_type)
{ {
afi_t install_afi; 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->installed = false;
pnhgc->valid = false; pnhgc->valid = false;
@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
struct listnode *node; struct listnode *node;
struct pbr_map_interface *pmi; struct pbr_map_interface *pmi;
struct nexthop *nh; 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) { if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) 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); pnhgc = hash_lookup(pbr_nhg_hash, &find);
nh = pbrms->nhg->nexthop; nh = pbrms->nhg->nexthop;
nh_afi = nh->type; nh_type = nh->type;
lup.nexthop = nh; lup.nexthop = nh;
pnhc = hash_lookup(pnhgc->nhh, &lup); pnhc = hash_lookup(pnhgc->nhh, &lup);
pnhc->parent = NULL; pnhc->parent = NULL;
hash_release(pnhgc->nhh, pnhc); hash_release(pnhgc->nhh, pnhc);
pbr_nh_delete(&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); hash_release(pbr_nhg_hash, pnhgc);
@ -653,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
struct pbr_nht_individual { struct pbr_nht_individual {
struct zapi_route *nhr; struct zapi_route *nhr;
struct interface *ifp;
uint32_t valid; 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); 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) static uint32_t pbr_nhg_hash_key(void *arg)
{ {
struct pbr_nexthop_group_cache *nhgc = 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); 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); extern void pbr_nht_init(void);
#endif #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, 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 NO_STR
"Set for the PBR-MAP\n" "Set for the PBR-MAP\n"
"Specify one of the nexthops in this map\n" "Specify one of the nexthops in this map\n"
"v4 Address\n" "v4 Address\n"
"v6 Address\n" "v6 Address\n"
"Interface to use\n" "Interface to use\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n" "If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n") "The nexthop-vrf Name\n")
{ {
@ -255,36 +261,28 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
memset(&nhop, 0, sizeof(nhop)); memset(&nhop, 0, sizeof(nhop));
nhop.vrf_id = vrf->vrf_id; nhop.vrf_id = vrf->vrf_id;
/* if (intf) {
* Make SA happy. CLIPPY is not going to give us a NULL nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
* addr. if (nhop.ifindex == IFINDEX_INTERNAL) {
*/ vty_out(vty,
assert(addr); "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) { if (addr->sa.sa_family == AF_INET) {
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
if (intf) { if (intf)
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); else
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; nhop.type = NEXTHOP_TYPE_IPV4;
} else { } else {
memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16); nhop.gate.ipv6 = addr->sin6.sin6_addr;
if (intf) { if (intf)
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); else {
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)) { if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
vty_out(vty, vty_out(vty,
"Specified a v6 LL with no interface, rejecting\n"); "Specified a v6 LL with no interface, rejecting\n");
@ -293,6 +291,8 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
nhop.type = NEXTHOP_TYPE_IPV6; nhop.type = NEXTHOP_TYPE_IPV6;
} }
} }
} else
nhop.type = NEXTHOP_TYPE_IFINDEX;
if (pbrms->nhg) if (pbrms->nhg)
nh = nexthop_exists(pbrms->nhg, &nhop); nh = nexthop_exists(pbrms->nhg, &nhop);
@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
pbr_map_check(pbrms); 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; return CMD_SUCCESS;
} }

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