mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 06:12:32 +00:00
Merge branch 'master' into evpn-session-vrf
This commit is contained in:
commit
d074383c62
@ -5,3 +5,4 @@
|
||||
**/*.lo
|
||||
**/*.so
|
||||
**/.libs
|
||||
docker/alpine/pkgs
|
||||
|
@ -175,13 +175,9 @@ EXTRA_DIST += \
|
||||
python/clidef.py \
|
||||
python/clippy/__init__.py \
|
||||
\
|
||||
redhat/frr.init \
|
||||
redhat/frr.service \
|
||||
redhat/daemons \
|
||||
redhat/frr.logrotate \
|
||||
redhat/frr.pam \
|
||||
redhat/frr.spec \
|
||||
redhat/README.rpm_build.md \
|
||||
\
|
||||
snapcraft/snapcraft.yaml \
|
||||
snapcraft/README.snap_build.md \
|
||||
|
@ -9,13 +9,13 @@ license="GPL-2.0"
|
||||
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
|
||||
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
||||
acct autoconf automake bash
|
||||
binutils binutils-libs bison bsd-compat-headers build-base
|
||||
binutils bison bsd-compat-headers build-base
|
||||
c-ares c-ares-dev ca-certificates cryptsetup-libs curl
|
||||
device-mapper-libs expat fakeroot flex fortify-headers gdbm
|
||||
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
|
||||
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
|
||||
libgomp libisoburn libisofs libltdl libressl libssh2
|
||||
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1
|
||||
libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1
|
||||
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
|
||||
patch pax-utils pcre perl pkgconf python2 python2-dev readline
|
||||
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
|
||||
@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
||||
checkdepends="pytest py-setuptools"
|
||||
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
|
||||
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
|
||||
source="$pkgname-$pkgver.tar.gz docker-start daemons"
|
||||
source="$pkgname-$pkgver.tar.gz"
|
||||
|
||||
builddir="$srcdir"/$pkgname-$pkgver
|
||||
|
||||
@ -60,8 +60,7 @@ package() {
|
||||
cd "$builddir"
|
||||
make DESTDIR="$pkgdir" install
|
||||
|
||||
install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
|
||||
install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
|
||||
install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir
|
||||
install -d "$pkgdir"/etc/init.d
|
||||
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
|
||||
}
|
||||
|
546
bfdd/bfd.c
546
bfdd/bfd.c
@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session);
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc);
|
||||
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
|
||||
struct sockaddr_any *local, bool mhop, const char *ifname,
|
||||
const char *vrfname);
|
||||
|
||||
static uint32_t ptm_bfd_gen_ID(void);
|
||||
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
|
||||
@ -52,66 +54,47 @@ static void bs_down_handler(struct bfd_session *bs, int nstate);
|
||||
static void bs_init_handler(struct bfd_session *bs, int nstate);
|
||||
static void bs_up_handler(struct bfd_session *bs, int nstate);
|
||||
|
||||
/* Zeroed array with the size of an IPv6 address. */
|
||||
struct in6_addr zero_addr;
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc)
|
||||
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
|
||||
struct sockaddr_any *local, bool mhop, const char *ifname,
|
||||
const char *vrfname)
|
||||
{
|
||||
struct bfd_session_observer *bso;
|
||||
struct bfd_session *bs = NULL;
|
||||
bool is_shop, is_ipv4;
|
||||
|
||||
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
|
||||
bs = bso->bso_bs;
|
||||
|
||||
is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
||||
is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
|
||||
/* Quick checks first. */
|
||||
if (is_shop != (!bpc->bpc_mhop))
|
||||
continue;
|
||||
if (is_ipv4 != bpc->bpc_ipv4)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Slow lookup without hash because we don't have all
|
||||
* information yet.
|
||||
*/
|
||||
if (is_shop) {
|
||||
if (strcmp(bs->ifname, bpc->bpc_localif))
|
||||
continue;
|
||||
if (memcmp(&bs->shop.peer, &bpc->bpc_peer,
|
||||
sizeof(bs->shop.peer)))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(bs->vrfname, bpc->bpc_vrfname))
|
||||
continue;
|
||||
if (memcmp(&bs->mhop.peer, &bpc->bpc_peer,
|
||||
sizeof(bs->mhop.peer)))
|
||||
continue;
|
||||
if (memcmp(&bs->mhop.local, &bpc->bpc_local,
|
||||
sizeof(bs->mhop.local)))
|
||||
continue;
|
||||
memset(key, 0, sizeof(*key));
|
||||
|
||||
switch (peer->sa_sin.sin_family) {
|
||||
case AF_INET:
|
||||
key->family = AF_INET;
|
||||
memcpy(&key->peer, &peer->sa_sin.sin_addr,
|
||||
sizeof(peer->sa_sin.sin_addr));
|
||||
memcpy(&key->local, &local->sa_sin.sin_addr,
|
||||
sizeof(local->sa_sin.sin_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
key->family = AF_INET6;
|
||||
memcpy(&key->peer, &peer->sa_sin6.sin6_addr,
|
||||
sizeof(peer->sa_sin6.sin6_addr));
|
||||
memcpy(&key->local, &local->sa_sin6.sin6_addr,
|
||||
sizeof(local->sa_sin6.sin6_addr));
|
||||
break;
|
||||
}
|
||||
if (bso == NULL)
|
||||
bs = NULL;
|
||||
|
||||
return bs;
|
||||
key->mhop = mhop;
|
||||
if (ifname && ifname[0])
|
||||
strlcpy(key->ifname, ifname, sizeof(key->ifname));
|
||||
if (vrfname && vrfname[0])
|
||||
strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
|
||||
}
|
||||
|
||||
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
||||
{
|
||||
struct bfd_session *bs;
|
||||
struct peer_label *pl;
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf;
|
||||
struct bfd_mhop_key mhop;
|
||||
struct bfd_shop_key shop;
|
||||
struct bfd_key key;
|
||||
|
||||
/* Try to find label first. */
|
||||
if (bpc->bpc_has_label) {
|
||||
@ -123,38 +106,10 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
||||
}
|
||||
|
||||
/* Otherwise fallback to peer/local hash lookup. */
|
||||
if (bpc->bpc_mhop) {
|
||||
memset(&mhop, 0, sizeof(mhop));
|
||||
mhop.peer = bpc->bpc_peer;
|
||||
mhop.local = bpc->bpc_local;
|
||||
if (bpc->bpc_has_vrfname) {
|
||||
vrf = vrf_lookup_by_name(bpc->bpc_vrfname);
|
||||
if (vrf == NULL)
|
||||
return NULL;
|
||||
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
|
||||
bpc->bpc_localif, bpc->bpc_vrfname);
|
||||
|
||||
mhop.vrfid = vrf->vrf_id;
|
||||
}
|
||||
|
||||
bs = bfd_mhop_lookup(mhop);
|
||||
} else {
|
||||
memset(&shop, 0, sizeof(shop));
|
||||
shop.peer = bpc->bpc_peer;
|
||||
if (bpc->bpc_has_localif) {
|
||||
ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif);
|
||||
if (ifp == NULL)
|
||||
return NULL;
|
||||
|
||||
shop.ifindex = ifp->ifindex;
|
||||
}
|
||||
|
||||
bs = bfd_shop_lookup(shop);
|
||||
}
|
||||
|
||||
if (bs != NULL)
|
||||
return bs;
|
||||
|
||||
/* Search for entries that are incomplete. */
|
||||
return bs_peer_waiting_find(bpc);
|
||||
return bfd_key_lookup(key);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
||||
*/
|
||||
int bfd_session_enable(struct bfd_session *bs)
|
||||
{
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct interface *ifp = NULL;
|
||||
struct vrf *vrf = NULL;
|
||||
int psock;
|
||||
@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
|
||||
* If the interface or VRF doesn't exist, then we must register
|
||||
* the session but delay its start.
|
||||
*/
|
||||
if (bs->ifname[0] != 0) {
|
||||
ifp = if_lookup_by_name_all_vrf(bs->ifname);
|
||||
if (bs->key.ifname[0]) {
|
||||
ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
|
||||
if (ifp == NULL) {
|
||||
log_error(
|
||||
"session-enable: specified interface doesn't exists.");
|
||||
@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs)
|
||||
|
||||
vrf = vrf_lookup_by_id(ifp->vrf_id);
|
||||
if (vrf == NULL) {
|
||||
log_error("session-enable: specified VRF doesn't exists.");
|
||||
log_error(
|
||||
"session-enable: specified VRF doesn't exists.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bs->vrfname[0] != 0) {
|
||||
vrf = vrf_lookup_by_name(bs->vrfname);
|
||||
if (bs->key.vrfname[0]) {
|
||||
vrf = vrf_lookup_by_name(bs->key.vrfname);
|
||||
if (vrf == NULL) {
|
||||
log_error("session-enable: specified VRF doesn't exists.");
|
||||
log_error(
|
||||
"session-enable: specified VRF doesn't exists.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -202,26 +158,15 @@ int bfd_session_enable(struct bfd_session *bs)
|
||||
if (bs->vrf == NULL)
|
||||
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
||||
|
||||
if (bs->ifname[0] != 0 &&
|
||||
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
|
||||
if (bs->key.ifname[0]
|
||||
&& BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
|
||||
bs->ifp = ifp;
|
||||
|
||||
/* Set the IPv6 scope id for link-local addresses. */
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
|
||||
sin6 = &bs->mhop.peer.sa_sin6;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_scope_id = bs->ifp != NULL
|
||||
? bs->ifp->ifindex
|
||||
: IFINDEX_INTERNAL;
|
||||
|
||||
sin6 = &bs->mhop.local.sa_sin6;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_scope_id = bs->ifp != NULL
|
||||
? bs->ifp->ifindex
|
||||
: IFINDEX_INTERNAL;
|
||||
|
||||
bs->local_ip.sa_sin6 = *sin6;
|
||||
bs->local_address.sa_sin6 = *sin6;
|
||||
/* Sanity check: don't leak open sockets. */
|
||||
if (bs->sock != -1) {
|
||||
zlog_debug("session-enable: previous socket open");
|
||||
close(bs->sock);
|
||||
bs->sock = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -232,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs)
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
|
||||
psock = bp_peer_socket(bs);
|
||||
if (psock == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
} else {
|
||||
psock = bp_peer_socketv6(bs);
|
||||
if (psock == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -247,25 +192,6 @@ int bfd_session_enable(struct bfd_session *bs)
|
||||
bfd_recvtimer_update(bs);
|
||||
ptm_bfd_start_xmt_timer(bs, false);
|
||||
|
||||
/* Registrate session into data structures. */
|
||||
bs->discrs.my_discr = ptm_bfd_gen_ID();
|
||||
bfd_id_insert(bs);
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
if (vrf != NULL)
|
||||
bs->mhop.vrfid = vrf->vrf_id;
|
||||
else
|
||||
bs->mhop.vrfid = VRF_DEFAULT;
|
||||
|
||||
bfd_mhop_insert(bs);
|
||||
} else {
|
||||
if (ifp != NULL)
|
||||
bs->shop.ifindex = ifp->ifindex;
|
||||
else
|
||||
bs->shop.ifindex = IFINDEX_INTERNAL;
|
||||
|
||||
bfd_shop_insert(bs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -288,13 +214,6 @@ void bfd_session_disable(struct bfd_session *bs)
|
||||
bfd_echo_recvtimer_delete(bs);
|
||||
bfd_xmttimer_delete(bs);
|
||||
bfd_echo_xmttimer_delete(bs);
|
||||
|
||||
/* Unregister session from hashes to avoid unwanted activation. */
|
||||
bfd_id_delete(bs->discrs.my_discr);
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||
bfd_mhop_delete(bs->mhop);
|
||||
else
|
||||
bfd_shop_delete(bs->shop);
|
||||
}
|
||||
|
||||
static uint32_t ptm_bfd_gen_ID(void)
|
||||
@ -438,21 +357,20 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
|
||||
if (bs == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Remove unused fields. */
|
||||
switch (sa->sa_sin.sin_family) {
|
||||
switch (bs->key.family) {
|
||||
case AF_INET:
|
||||
sa->sa_sin.sin_port = 0;
|
||||
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
|
||||
return bs;
|
||||
if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
|
||||
sizeof(sa->sa_sin.sin_addr)))
|
||||
return NULL;
|
||||
break;
|
||||
case AF_INET6:
|
||||
sa->sa_sin6.sin6_port = 0;
|
||||
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
|
||||
return bs;
|
||||
if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
|
||||
sizeof(sa->sa_sin6.sin6_addr)))
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return bs;
|
||||
}
|
||||
|
||||
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
||||
@ -461,32 +379,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
||||
ifindex_t ifindex, vrf_id_t vrfid,
|
||||
bool is_mhop)
|
||||
{
|
||||
struct bfd_session *l_bfd = NULL;
|
||||
struct bfd_mhop_key mhop;
|
||||
struct bfd_shop_key shop;
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf;
|
||||
struct bfd_key key;
|
||||
|
||||
/* Find our session using the ID signaled by the remote end. */
|
||||
if (cp->discrs.remote_discr)
|
||||
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
|
||||
|
||||
/* Search for session without using discriminator. */
|
||||
if (is_mhop) {
|
||||
memset(&mhop, 0, sizeof(mhop));
|
||||
mhop.peer = *peer;
|
||||
mhop.local = *local;
|
||||
mhop.vrfid = vrfid;
|
||||
ifp = if_lookup_by_index(ifindex, vrfid);
|
||||
if (vrfid == VRF_DEFAULT) {
|
||||
/*
|
||||
* Don't use the default vrf, otherwise we won't find
|
||||
* sessions that doesn't specify it.
|
||||
*/
|
||||
vrf = NULL;
|
||||
} else
|
||||
vrf = vrf_lookup_by_id(vrfid);
|
||||
|
||||
l_bfd = bfd_mhop_lookup(mhop);
|
||||
} else {
|
||||
memset(&shop, 0, sizeof(shop));
|
||||
shop.peer = *peer;
|
||||
shop.ifindex = ifindex;
|
||||
|
||||
l_bfd = bfd_shop_lookup(shop);
|
||||
}
|
||||
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
|
||||
vrf ? vrf->name : NULL);
|
||||
|
||||
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
|
||||
return l_bfd;
|
||||
return bfd_key_lookup(key);
|
||||
}
|
||||
|
||||
int bfd_xmt_cb(struct thread *t)
|
||||
@ -701,6 +617,9 @@ static void bfd_session_free(struct bfd_session *bs)
|
||||
|
||||
bfd_session_disable(bs);
|
||||
|
||||
bfd_key_delete(bs->key);
|
||||
bfd_id_delete(bs->discrs.my_discr);
|
||||
|
||||
/* Remove observer if any. */
|
||||
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
|
||||
if (bso->bso_bs != bs)
|
||||
@ -743,29 +662,47 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
||||
* start. See `bfd_session_enable` for more information.
|
||||
*/
|
||||
if (bpc->bpc_has_localif)
|
||||
strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname));
|
||||
strlcpy(bfd->key.ifname, bpc->bpc_localif,
|
||||
sizeof(bfd->key.ifname));
|
||||
|
||||
if (bpc->bpc_has_vrfname)
|
||||
strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
|
||||
|
||||
/* Add observer if we have moving parts. */
|
||||
if (bfd->ifname[0] || bfd->vrfname[0])
|
||||
bs_observer_add(bfd);
|
||||
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
|
||||
sizeof(bfd->key.vrfname));
|
||||
|
||||
/* Copy remaining data. */
|
||||
if (bpc->bpc_ipv4 == false)
|
||||
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
|
||||
|
||||
if (bpc->bpc_mhop) {
|
||||
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
|
||||
bfd->mhop.peer = bpc->bpc_peer;
|
||||
bfd->mhop.local = bpc->bpc_local;
|
||||
} else {
|
||||
bfd->shop.peer = bpc->bpc_peer;
|
||||
bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
|
||||
switch (bfd->key.family) {
|
||||
case AF_INET:
|
||||
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
|
||||
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
|
||||
memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr,
|
||||
sizeof(bpc->bpc_local.sa_sin.sin_addr));
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr,
|
||||
sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
|
||||
memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr,
|
||||
sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(1);
|
||||
break;
|
||||
}
|
||||
|
||||
bfd->local_ip = bpc->bpc_local;
|
||||
bfd->local_address = bpc->bpc_local;
|
||||
if (bpc->bpc_mhop)
|
||||
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
|
||||
|
||||
bfd->key.mhop = bpc->bpc_mhop;
|
||||
|
||||
/* Registrate session into data structures. */
|
||||
bfd_key_insert(bfd);
|
||||
bfd->discrs.my_discr = ptm_bfd_gen_ID();
|
||||
bfd_id_insert(bfd);
|
||||
|
||||
/* Try to enable session and schedule for packet receive/send. */
|
||||
if (bfd_session_enable(bfd) == -1) {
|
||||
@ -774,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add observer if we have moving parts. */
|
||||
if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
|
||||
bs_observer_add(bfd);
|
||||
|
||||
/* Apply other configurations. */
|
||||
_bfd_session_update(bfd, bpc);
|
||||
|
||||
@ -1219,35 +1160,26 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen)
|
||||
snprintf(buf, buflen, "%u second(s)", second);
|
||||
}
|
||||
|
||||
const char *bs_to_string(struct bfd_session *bs)
|
||||
const char *bs_to_string(const struct bfd_session *bs)
|
||||
{
|
||||
static char buf[256];
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
int pos;
|
||||
bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
||||
|
||||
pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos,
|
||||
" peer:%s local:%s", satostr(&bs->mhop.peer),
|
||||
satostr(&bs->mhop.local));
|
||||
|
||||
if (bs->mhop.vrfid != VRF_DEFAULT)
|
||||
snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u",
|
||||
bs->mhop.vrfid);
|
||||
} else {
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
|
||||
satostr(&bs->shop.peer));
|
||||
|
||||
if (bs->local_address.sa_sin.sin_family)
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos,
|
||||
" local:%s",
|
||||
satostr(&bs->local_address));
|
||||
|
||||
if (bs->shop.ifindex)
|
||||
snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u",
|
||||
bs->shop.ifindex);
|
||||
}
|
||||
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
|
||||
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
|
||||
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
if (bs->key.vrfname[0])
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
|
||||
bs->key.vrfname);
|
||||
if (bs->key.ifname[0])
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
|
||||
bs->key.ifname);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -1255,16 +1187,25 @@ int bs_observer_add(struct bfd_session *bs)
|
||||
{
|
||||
struct bfd_session_observer *bso;
|
||||
|
||||
bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
|
||||
bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
|
||||
bso->bso_isaddress = false;
|
||||
bso->bso_bs = bs;
|
||||
bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
||||
if (bso->bso_isinterface)
|
||||
strlcpy(bso->bso_entryname, bs->ifname,
|
||||
strlcpy(bso->bso_entryname, bs->key.ifname,
|
||||
sizeof(bso->bso_entryname));
|
||||
else
|
||||
strlcpy(bso->bso_entryname, bs->vrfname,
|
||||
strlcpy(bso->bso_entryname, bs->key.vrfname,
|
||||
sizeof(bso->bso_entryname));
|
||||
|
||||
/* Handle socket binding failures caused by missing local addresses. */
|
||||
if (bs->sock == -1) {
|
||||
bso->bso_isaddress = true;
|
||||
bso->bso_addr.family = bs->key.family;
|
||||
memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
|
||||
sizeof(bs->key.local));
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
|
||||
|
||||
return 0;
|
||||
@ -1276,21 +1217,59 @@ void bs_observer_del(struct bfd_session_observer *bso)
|
||||
XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
|
||||
}
|
||||
|
||||
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
|
||||
{
|
||||
memset(bpc, 0, sizeof(*bpc));
|
||||
|
||||
bpc->bpc_ipv4 = (bs->key.family == AF_INET);
|
||||
bpc->bpc_mhop = bs->key.mhop;
|
||||
|
||||
switch (bs->key.family) {
|
||||
case AF_INET:
|
||||
bpc->bpc_peer.sa_sin.sin_family = AF_INET;
|
||||
memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer,
|
||||
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
|
||||
|
||||
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) {
|
||||
bpc->bpc_local.sa_sin.sin_family = AF_INET6;
|
||||
memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local,
|
||||
sizeof(bpc->bpc_local.sa_sin.sin_addr));
|
||||
}
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
bpc->bpc_peer.sa_sin.sin_family = AF_INET6;
|
||||
memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer,
|
||||
sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
|
||||
|
||||
bpc->bpc_local.sa_sin6.sin6_family = AF_INET6;
|
||||
memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local,
|
||||
sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
|
||||
break;
|
||||
}
|
||||
|
||||
if (bs->key.ifname[0]) {
|
||||
bpc->bpc_has_localif = true;
|
||||
strlcpy(bpc->bpc_localif, bs->key.ifname,
|
||||
sizeof(bpc->bpc_localif));
|
||||
}
|
||||
|
||||
if (bs->key.vrfname[0]) {
|
||||
bpc->bpc_has_vrfname = true;
|
||||
strlcpy(bpc->bpc_vrfname, bs->key.vrfname,
|
||||
sizeof(bpc->bpc_vrfname));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BFD hash data structures to find sessions.
|
||||
*/
|
||||
static struct hash *bfd_id_hash;
|
||||
static struct hash *bfd_shop_hash;
|
||||
static struct hash *bfd_mhop_hash;
|
||||
static struct hash *bfd_key_hash;
|
||||
|
||||
static unsigned int bfd_id_hash_do(void *p);
|
||||
static unsigned int bfd_shop_hash_do(void *p);
|
||||
static unsigned int bfd_mhop_hash_do(void *p);
|
||||
|
||||
static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop);
|
||||
static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop);
|
||||
static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop);
|
||||
static unsigned int bfd_key_hash_do(void *p);
|
||||
|
||||
static void _bfd_free(struct hash_bucket *hb,
|
||||
void *arg __attribute__((__unused__)));
|
||||
@ -1311,73 +1290,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2)
|
||||
}
|
||||
|
||||
/* BFD hash for single hop. */
|
||||
static unsigned int bfd_shop_hash_do(void *p)
|
||||
static unsigned int bfd_key_hash_do(void *p)
|
||||
{
|
||||
struct bfd_session *bs = p;
|
||||
|
||||
return jhash(&bs->shop, sizeof(bs->shop), 0);
|
||||
return jhash(&bs->key, sizeof(bs->key), 0);
|
||||
}
|
||||
|
||||
static bool bfd_shop_hash_cmp(const void *n1, const void *n2)
|
||||
static bool bfd_key_hash_cmp(const void *n1, const void *n2)
|
||||
{
|
||||
const struct bfd_session *bs1 = n1, *bs2 = n2;
|
||||
|
||||
return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
|
||||
return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0;
|
||||
}
|
||||
|
||||
/* BFD hash for multi hop. */
|
||||
static unsigned int bfd_mhop_hash_do(void *p)
|
||||
{
|
||||
struct bfd_session *bs = p;
|
||||
|
||||
return jhash(&bs->mhop, sizeof(bs->mhop), 0);
|
||||
}
|
||||
|
||||
static bool bfd_mhop_hash_cmp(const void *n1, const void *n2)
|
||||
{
|
||||
const struct bfd_session *bs1 = n1, *bs2 = n2;
|
||||
|
||||
return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0;
|
||||
}
|
||||
|
||||
/* Helper functions */
|
||||
static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop)
|
||||
{
|
||||
bs->shop = *shop;
|
||||
|
||||
/* Remove unused fields. */
|
||||
switch (bs->shop.peer.sa_sin.sin_family) {
|
||||
case AF_INET:
|
||||
bs->shop.peer.sa_sin.sin_port = 0;
|
||||
break;
|
||||
case AF_INET6:
|
||||
bs->shop.peer.sa_sin6.sin6_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop)
|
||||
{
|
||||
_shop_key(bs, shop);
|
||||
bs->shop.ifindex = IFINDEX_INTERNAL;
|
||||
}
|
||||
|
||||
static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop)
|
||||
{
|
||||
bs->mhop = *mhop;
|
||||
|
||||
/* Remove unused fields. */
|
||||
switch (bs->mhop.peer.sa_sin.sin_family) {
|
||||
case AF_INET:
|
||||
bs->mhop.peer.sa_sin.sin_port = 0;
|
||||
bs->mhop.local.sa_sin.sin_port = 0;
|
||||
break;
|
||||
case AF_INET6:
|
||||
bs->mhop.peer.sa_sin6.sin6_port = 0;
|
||||
bs->mhop.local.sa_sin6.sin6_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash public interface / exported functions.
|
||||
@ -1393,34 +1319,35 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
|
||||
return hash_lookup(bfd_id_hash, &bs);
|
||||
}
|
||||
|
||||
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop)
|
||||
struct bfd_session *bfd_key_lookup(struct bfd_key key)
|
||||
{
|
||||
struct bfd_session bs, *bsp;
|
||||
|
||||
_shop_key(&bs, &shop);
|
||||
bs.key = key;
|
||||
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||
|
||||
bsp = hash_lookup(bfd_shop_hash, &bs);
|
||||
if (bsp == NULL && bs.shop.ifindex != 0) {
|
||||
/*
|
||||
* Since the local interface spec is optional, try
|
||||
* searching the key without it as well.
|
||||
*/
|
||||
_shop_key2(&bs, &shop);
|
||||
bsp = hash_lookup(bfd_shop_hash, &bs);
|
||||
/* Handle cases where local-address is optional. */
|
||||
if (bsp == NULL && bs.key.family == AF_INET) {
|
||||
memset(&bs.key.local, 0, sizeof(bs.key.local));
|
||||
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||
}
|
||||
|
||||
/* Handle cases where ifname is optional. */
|
||||
bs.key = key;
|
||||
if (bsp == NULL && bs.key.ifname[0]) {
|
||||
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
|
||||
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||
|
||||
/* Handle cases where local-address and ifname are optional. */
|
||||
if (bsp == NULL && bs.key.family == AF_INET) {
|
||||
memset(&bs.key.local, 0, sizeof(bs.key.local));
|
||||
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||
}
|
||||
}
|
||||
|
||||
return bsp;
|
||||
}
|
||||
|
||||
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
|
||||
{
|
||||
struct bfd_session bs;
|
||||
|
||||
_mhop_key(&bs, &mhop);
|
||||
|
||||
return hash_lookup(bfd_mhop_hash, &bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete functions.
|
||||
*
|
||||
@ -1440,31 +1367,18 @@ struct bfd_session *bfd_id_delete(uint32_t id)
|
||||
return hash_release(bfd_id_hash, &bs);
|
||||
}
|
||||
|
||||
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop)
|
||||
struct bfd_session *bfd_key_delete(struct bfd_key key)
|
||||
{
|
||||
struct bfd_session bs, *bsp;
|
||||
|
||||
_shop_key(&bs, &shop);
|
||||
bsp = hash_release(bfd_shop_hash, &bs);
|
||||
if (bsp == NULL && shop.ifindex != 0) {
|
||||
/*
|
||||
* Since the local interface spec is optional, try
|
||||
* searching the key without it as well.
|
||||
*/
|
||||
_shop_key2(&bs, &shop);
|
||||
bsp = hash_release(bfd_shop_hash, &bs);
|
||||
bs.key = key;
|
||||
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||
if (bsp == NULL && key.ifname[0]) {
|
||||
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
|
||||
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||
}
|
||||
|
||||
return bsp;
|
||||
}
|
||||
|
||||
struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop)
|
||||
{
|
||||
struct bfd_session bs;
|
||||
|
||||
_mhop_key(&bs, &mhop);
|
||||
|
||||
return hash_release(bfd_mhop_hash, &bs);
|
||||
return hash_release(bfd_key_hash, bsp);
|
||||
}
|
||||
|
||||
/* Iteration functions. */
|
||||
@ -1473,14 +1387,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg)
|
||||
hash_iterate(bfd_id_hash, hif, arg);
|
||||
}
|
||||
|
||||
void bfd_shop_iterate(hash_iter_func hif, void *arg)
|
||||
void bfd_key_iterate(hash_iter_func hif, void *arg)
|
||||
{
|
||||
hash_iterate(bfd_shop_hash, hif, arg);
|
||||
}
|
||||
|
||||
void bfd_mhop_iterate(hash_iter_func hif, void *arg)
|
||||
{
|
||||
hash_iterate(bfd_mhop_hash, hif, arg);
|
||||
hash_iterate(bfd_key_hash, hif, arg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1494,24 +1403,17 @@ bool bfd_id_insert(struct bfd_session *bs)
|
||||
return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
|
||||
}
|
||||
|
||||
bool bfd_shop_insert(struct bfd_session *bs)
|
||||
bool bfd_key_insert(struct bfd_session *bs)
|
||||
{
|
||||
return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
|
||||
}
|
||||
|
||||
bool bfd_mhop_insert(struct bfd_session *bs)
|
||||
{
|
||||
return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
|
||||
return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs);
|
||||
}
|
||||
|
||||
void bfd_initialize(void)
|
||||
{
|
||||
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
|
||||
"BFD discriminator hash");
|
||||
bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
|
||||
"BFD single hop hash");
|
||||
bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
|
||||
"BFD multihop hop hash");
|
||||
"BFD session discriminator hash");
|
||||
bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
|
||||
"BFD session hash");
|
||||
}
|
||||
|
||||
static void _bfd_free(struct hash_bucket *hb,
|
||||
@ -1532,11 +1434,9 @@ void bfd_shutdown(void)
|
||||
* assert() here to make sure it really happened.
|
||||
*/
|
||||
bfd_id_iterate(_bfd_free, NULL);
|
||||
assert(bfd_shop_hash->count == 0);
|
||||
assert(bfd_mhop_hash->count == 0);
|
||||
assert(bfd_key_hash->count == 0);
|
||||
|
||||
/* Now free the hashes themselves. */
|
||||
hash_free(bfd_id_hash);
|
||||
hash_free(bfd_shop_hash);
|
||||
hash_free(bfd_mhop_hash);
|
||||
hash_free(bfd_key_hash);
|
||||
}
|
||||
|
59
bfdd/bfd.h
59
bfdd/bfd.h
@ -173,15 +173,13 @@ enum bfd_session_flags {
|
||||
#define BFD_CHECK_FLAG(field, flag) (field & flag)
|
||||
|
||||
/* BFD session hash keys */
|
||||
struct bfd_shop_key {
|
||||
struct sockaddr_any peer;
|
||||
ifindex_t ifindex;
|
||||
};
|
||||
|
||||
struct bfd_mhop_key {
|
||||
struct sockaddr_any peer;
|
||||
struct sockaddr_any local;
|
||||
vrf_id_t vrfid;
|
||||
struct bfd_key {
|
||||
uint16_t family;
|
||||
uint8_t mhop;
|
||||
struct in6_addr peer;
|
||||
struct in6_addr local;
|
||||
char ifname[MAXNAMELEN];
|
||||
char vrfname[MAXNAMELEN];
|
||||
};
|
||||
|
||||
struct bfd_session_stats {
|
||||
@ -227,19 +225,14 @@ struct bfd_session {
|
||||
uint8_t polling;
|
||||
|
||||
/* This and the localDiscr are the keys to state info */
|
||||
struct bfd_key key;
|
||||
struct peer_label *pl;
|
||||
union {
|
||||
struct bfd_shop_key shop;
|
||||
struct bfd_mhop_key mhop;
|
||||
};
|
||||
int sock;
|
||||
|
||||
struct sockaddr_any local_address;
|
||||
struct sockaddr_any local_ip;
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf;
|
||||
char ifname[MAXNAMELEN];
|
||||
char vrfname[MAXNAMELEN];
|
||||
|
||||
int sock;
|
||||
|
||||
/* BFD session flags */
|
||||
enum bfd_session_flags flags;
|
||||
@ -281,7 +274,11 @@ struct bfd_state_str_list {
|
||||
struct bfd_session_observer {
|
||||
struct bfd_session *bso_bs;
|
||||
bool bso_isinterface;
|
||||
char bso_entryname[MAXNAMELEN];
|
||||
bool bso_isaddress;
|
||||
union {
|
||||
char bso_entryname[MAXNAMELEN];
|
||||
struct prefix bso_addr;
|
||||
};
|
||||
|
||||
TAILQ_ENTRY(bfd_session_observer) bso_entry;
|
||||
};
|
||||
@ -531,38 +528,28 @@ const char *satostr(struct sockaddr_any *sa);
|
||||
const char *diag2str(uint8_t diag);
|
||||
int strtosa(const char *addr, struct sockaddr_any *sa);
|
||||
void integer2timestr(uint64_t time, char *buf, size_t buflen);
|
||||
const char *bs_to_string(struct bfd_session *bs);
|
||||
const char *bs_to_string(const struct bfd_session *bs);
|
||||
|
||||
int bs_observer_add(struct bfd_session *bs);
|
||||
void bs_observer_del(struct bfd_session_observer *bso);
|
||||
|
||||
void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
|
||||
|
||||
/* BFD hash data structures interface */
|
||||
void bfd_initialize(void);
|
||||
void bfd_shutdown(void);
|
||||
struct bfd_session *bfd_id_lookup(uint32_t id);
|
||||
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
|
||||
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop);
|
||||
struct bfd_vrf *bfd_vrf_lookup(int vrf_id);
|
||||
struct bfd_iface *bfd_iface_lookup(const char *ifname);
|
||||
struct bfd_session *bfd_key_lookup(struct bfd_key key);
|
||||
|
||||
struct bfd_session *bfd_id_delete(uint32_t id);
|
||||
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
|
||||
struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop);
|
||||
struct bfd_vrf *bfd_vrf_delete(int vrf_id);
|
||||
struct bfd_iface *bfd_iface_delete(const char *ifname);
|
||||
struct bfd_session *bfd_key_delete(struct bfd_key key);
|
||||
|
||||
bool bfd_id_insert(struct bfd_session *bs);
|
||||
bool bfd_shop_insert(struct bfd_session *bs);
|
||||
bool bfd_mhop_insert(struct bfd_session *bs);
|
||||
bool bfd_vrf_insert(struct bfd_vrf *vrf);
|
||||
bool bfd_iface_insert(struct bfd_iface *iface);
|
||||
bool bfd_key_insert(struct bfd_session *bs);
|
||||
|
||||
typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
|
||||
void bfd_id_iterate(hash_iter_func hif, void *arg);
|
||||
void bfd_shop_iterate(hash_iter_func hif, void *arg);
|
||||
void bfd_mhop_iterate(hash_iter_func hif, void *arg);
|
||||
void bfd_vrf_iterate(hash_iter_func hif, void *arg);
|
||||
void bfd_iface_iterate(hash_iter_func hif, void *arg);
|
||||
void bfd_key_iterate(hash_iter_func hif, void *arg);
|
||||
|
||||
/* Export callback functions for `event.c`. */
|
||||
extern struct thread_master *master;
|
||||
@ -572,6 +559,8 @@ int bfd_echo_recvtimer_cb(struct thread *t);
|
||||
int bfd_xmt_cb(struct thread *t);
|
||||
int bfd_echo_xmt_cb(struct thread *t);
|
||||
|
||||
extern struct in6_addr zero_addr;
|
||||
|
||||
|
||||
/*
|
||||
* bfdd_vty.c
|
||||
|
@ -79,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
|
||||
memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr));
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
|
||||
sin6.sin6_scope_id = bs->ifp->ifindex;
|
||||
|
||||
sin6.sin6_port =
|
||||
(port) ? *port
|
||||
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||
@ -92,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
|
||||
} else {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
|
||||
memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr));
|
||||
sin.sin_port =
|
||||
(port) ? *port
|
||||
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||
@ -120,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
|
||||
|
||||
void ptm_bfd_echo_snd(struct bfd_session *bfd)
|
||||
{
|
||||
struct sockaddr_any *sa;
|
||||
struct sockaddr *sa;
|
||||
socklen_t salen;
|
||||
int sd;
|
||||
struct bfd_echo_pkt bep;
|
||||
@ -135,31 +138,36 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
|
||||
bep.len = BFD_ECHO_PKT_LEN;
|
||||
bep.my_discr = htonl(bfd->discrs.my_discr);
|
||||
|
||||
sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer
|
||||
: &bfd->shop.peer;
|
||||
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
|
||||
sd = bglobal.bg_echov6;
|
||||
sin6 = sa->sa_sin6;
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
|
||||
if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
|
||||
sin6.sin6_scope_id = bfd->ifp->ifindex;
|
||||
|
||||
sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
sin6.sin6_len = sizeof(sin6);
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
||||
|
||||
sa = (struct sockaddr_any *)&sin6;
|
||||
sa = (struct sockaddr *)&sin6;
|
||||
salen = sizeof(sin6);
|
||||
} else {
|
||||
sd = bglobal.bg_echo;
|
||||
sin = sa->sa_sin;
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin.sin_family = AF_INET;
|
||||
memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
|
||||
sin.sin_port = htons(BFD_DEF_ECHO_PORT);
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
sin.sin_len = sizeof(sin);
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
||||
|
||||
sa = (struct sockaddr_any *)&sin;
|
||||
sa = (struct sockaddr *)&sin;
|
||||
salen = sizeof(sin);
|
||||
}
|
||||
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
|
||||
(struct sockaddr *)sa, salen)
|
||||
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
|
||||
salen)
|
||||
== -1)
|
||||
return;
|
||||
|
||||
@ -602,8 +610,8 @@ int bfd_recv_cb(struct thread *t)
|
||||
bfd->mh_ttl, BFD_TTL_VAL);
|
||||
return 0;
|
||||
}
|
||||
} else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
|
||||
bfd->local_ip = local;
|
||||
} else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
|
||||
bfd->local_address = local;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -917,25 +925,26 @@ int bp_peer_socket(const struct bfd_session *bs)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
|
||||
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
|
||||
if (bs->key.ifname[0]) {
|
||||
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
|
||||
bs->mhop.vrfid != VRF_DEFAULT) {
|
||||
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
|
||||
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
|
||||
&& bs->key.vrfname[0]) {
|
||||
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find an available source port in the proper range */
|
||||
sin = bs->local_ip.sa_sin;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
sin.sin_len = sizeof(sin);
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
||||
memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
@ -987,20 +996,23 @@ int bp_peer_socketv6(const struct bfd_session *bs)
|
||||
}
|
||||
|
||||
/* Find an available source port in the proper range */
|
||||
sin6 = bs->local_ip.sa_sin6;
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
sin6.sin6_len = sizeof(sin6);
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
||||
memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr));
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
|
||||
sin6.sin6_scope_id = bs->ifp->ifindex;
|
||||
|
||||
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
|
||||
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
|
||||
if (bs->key.ifname[0]) {
|
||||
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
|
||||
bs->mhop.vrfid != VRF_DEFAULT) {
|
||||
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
|
||||
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
|
||||
&& bs->key.vrfname[0]) {
|
||||
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
108
bfdd/bfdd_vty.c
108
bfdd/bfdd_vty.c
@ -79,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
|
||||
const char *local_str, const char *ifname,
|
||||
const char *vrfname);
|
||||
|
||||
|
||||
/*
|
||||
* Commands definition.
|
||||
*/
|
||||
@ -369,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
|
||||
*/
|
||||
static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
|
||||
{
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
vty_out(vty, "\tpeer %s",
|
||||
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||
vty_out(vty, " multihop");
|
||||
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
|
||||
if (bs->vrfname[0])
|
||||
vty_out(vty, " vrf %s", bs->vrfname);
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
|
||||
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
|
||||
vty_out(vty, " local-address %s",
|
||||
satostr(&bs->local_address));
|
||||
if (bs->ifname[0])
|
||||
vty_out(vty, " interface %s", bs->ifname);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||
vty_out(vty, " local-address %s",
|
||||
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
|
||||
if (bs->key.vrfname[0])
|
||||
vty_out(vty, " vrf %s", bs->key.vrfname);
|
||||
if (bs->key.ifname[0])
|
||||
vty_out(vty, " interface %s", bs->key.ifname);
|
||||
vty_out(vty, "\n");
|
||||
|
||||
if (bs->pl)
|
||||
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
|
||||
@ -453,22 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
|
||||
static struct json_object *_peer_json_header(struct bfd_session *bs)
|
||||
{
|
||||
struct json_object *jo = json_object_new_object();
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
if (bs->key.mhop)
|
||||
json_object_boolean_true_add(jo, "multihop");
|
||||
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
|
||||
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
|
||||
if (bs->vrfname[0])
|
||||
json_object_string_add(jo, "vrf", bs->vrfname);
|
||||
} else {
|
||||
else
|
||||
json_object_boolean_false_add(jo, "multihop");
|
||||
json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
|
||||
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
|
||||
json_object_string_add(jo, "local",
|
||||
satostr(&bs->local_address));
|
||||
if (bs->ifname[0])
|
||||
json_object_string_add(jo, "interface", bs->ifname);
|
||||
}
|
||||
|
||||
json_object_string_add(jo, "peer",
|
||||
inet_ntop(bs->key.family, &bs->key.peer,
|
||||
addr_buf, sizeof(addr_buf)));
|
||||
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||
json_object_string_add(jo, "local",
|
||||
inet_ntop(bs->key.family, &bs->key.local,
|
||||
addr_buf, sizeof(addr_buf)));
|
||||
|
||||
if (bs->key.vrfname[0])
|
||||
json_object_string_add(jo, "vrf", bs->key.vrfname);
|
||||
if (bs->key.ifname[0])
|
||||
json_object_string_add(jo, "interface", bs->key.ifname);
|
||||
|
||||
if (bs->pl)
|
||||
json_object_string_add(jo, "label", bs->pl->pl_label);
|
||||
@ -916,25 +921,29 @@ static int bfdd_write_config(struct vty *vty)
|
||||
|
||||
static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
|
||||
{
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
vty_out(vty, " peer %s",
|
||||
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
|
||||
if (bs->key.mhop)
|
||||
vty_out(vty, " multihop");
|
||||
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
|
||||
if (bs->vrfname[0])
|
||||
vty_out(vty, " vrf %s", bs->vrfname);
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
vty_out(vty, " peer %s", satostr(&bs->shop.peer));
|
||||
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
|
||||
vty_out(vty, " local-address %s",
|
||||
satostr(&bs->local_address));
|
||||
if (bs->ifname[0])
|
||||
vty_out(vty, " interface %s", bs->ifname);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||
vty_out(vty, " local-address %s",
|
||||
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||
sizeof(addr_buf)));
|
||||
|
||||
if (bs->key.vrfname[0])
|
||||
vty_out(vty, " vrf %s", bs->key.vrfname);
|
||||
if (bs->key.ifname[0])
|
||||
vty_out(vty, " interface %s", bs->key.ifname);
|
||||
vty_out(vty, "\n");
|
||||
|
||||
if (bs->sock == -1)
|
||||
vty_out(vty, " ! vrf or interface doesn't exist\n");
|
||||
vty_out(vty,
|
||||
" ! vrf, interface or local-address doesn't exist\n");
|
||||
|
||||
if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
|
||||
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
|
||||
@ -980,16 +989,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
|
||||
|
||||
static int bfdd_peer_write_config(struct vty *vty)
|
||||
{
|
||||
struct bfd_session_observer *bso;
|
||||
|
||||
bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
|
||||
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
|
||||
/* Only print disabled sessions here. */
|
||||
if (bso->bso_bs->sock != -1)
|
||||
continue;
|
||||
|
||||
_bfdd_peer_write_config(vty, bso->bso_bs);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo,
|
||||
log_debug("\tpeer-label: %s", sval);
|
||||
|
||||
/* Translate the label into BFD address keys. */
|
||||
bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
|
||||
bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH);
|
||||
if (bpc->bpc_mhop) {
|
||||
bpc->bpc_peer = pl->pl_bs->mhop.peer;
|
||||
bpc->bpc_local = pl->pl_bs->mhop.local;
|
||||
if (pl->pl_bs->mhop.vrfid != VRF_DEFAULT) {
|
||||
bpc->bpc_has_vrfname = true;
|
||||
strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name,
|
||||
sizeof(bpc->bpc_vrfname));
|
||||
}
|
||||
} else {
|
||||
bpc->bpc_peer = pl->pl_bs->shop.peer;
|
||||
if (pl->pl_bs->ifname[0]) {
|
||||
bpc->bpc_has_localif = true;
|
||||
strlcpy(bpc->bpc_localif, pl->pl_bs->ifname,
|
||||
sizeof(bpc->bpc_localif));
|
||||
}
|
||||
}
|
||||
bs_to_bpc(pl->pl_bs, bpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -519,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
|
||||
|
||||
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
|
||||
{
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
/* Add peer 'key' information. */
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
|
||||
json_object_boolean_true_add(jo, "ipv6");
|
||||
@ -528,21 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
json_object_boolean_true_add(jo, "multihop");
|
||||
json_object_string_add(jo, "peer-address",
|
||||
satostr(&bs->mhop.peer));
|
||||
inet_ntop(bs->key.family, &bs->key.peer,
|
||||
addr_buf, sizeof(addr_buf)));
|
||||
json_object_string_add(jo, "local-address",
|
||||
satostr(&bs->mhop.local));
|
||||
if (bs->vrfname[0])
|
||||
json_object_string_add(jo, "vrf-name", bs->vrfname);
|
||||
inet_ntop(bs->key.family, &bs->key.local,
|
||||
addr_buf, sizeof(addr_buf)));
|
||||
if (bs->key.vrfname[0])
|
||||
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
|
||||
} else {
|
||||
json_object_boolean_false_add(jo, "multihop");
|
||||
json_object_string_add(jo, "peer-address",
|
||||
satostr(&bs->shop.peer));
|
||||
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
|
||||
json_object_string_add(jo, "local-address",
|
||||
satostr(&bs->local_address));
|
||||
if (bs->ifname[0])
|
||||
inet_ntop(bs->key.family, &bs->key.peer,
|
||||
addr_buf, sizeof(addr_buf)));
|
||||
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||
json_object_string_add(
|
||||
jo, "local-address",
|
||||
inet_ntop(bs->key.family, &bs->key.local,
|
||||
addr_buf, sizeof(addr_buf)));
|
||||
if (bs->key.ifname[0])
|
||||
json_object_string_add(jo, "local-interface",
|
||||
bs->ifname);
|
||||
bs->key.ifname);
|
||||
}
|
||||
|
||||
if (bs->pl)
|
||||
|
@ -55,7 +55,7 @@ static struct zclient *zclient;
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa);
|
||||
static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
|
||||
|
||||
static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
|
||||
static int _ptm_msg_read(struct stream *msg, int command,
|
||||
@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line,
|
||||
#define DEBUG_PRINTBPC(bpc)
|
||||
#endif /* BFD_DEBUG */
|
||||
|
||||
static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
|
||||
static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
|
||||
{
|
||||
switch (sa->sa_sin.sin_family) {
|
||||
stream_putc(msg, family);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
stream_putc(msg, sa->sa_sin.sin_family);
|
||||
stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
|
||||
stream_put(msg, addr, sizeof(struct in_addr));
|
||||
stream_putc(msg, 32);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
stream_putc(msg, sa->sa_sin6.sin6_family);
|
||||
stream_put(msg, &sa->sa_sin6.sin6_addr,
|
||||
sizeof(sa->sa_sin6.sin6_addr));
|
||||
stream_put(msg, addr, sizeof(struct in6_addr));
|
||||
stream_putc(msg, 128);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
|
||||
int ptm_bfd_notify(struct bfd_session *bs)
|
||||
{
|
||||
struct stream *msg;
|
||||
struct sockaddr_any sac;
|
||||
|
||||
bs->stats.znotification++;
|
||||
|
||||
@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
|
||||
stream_putl(msg, IFINDEX_INTERNAL);
|
||||
|
||||
/* BFD destination prefix information. */
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||
_ptm_msg_address(msg, &bs->mhop.peer);
|
||||
else
|
||||
_ptm_msg_address(msg, &bs->shop.peer);
|
||||
_ptm_msg_address(msg, bs->key.family, &bs->key.peer);
|
||||
|
||||
/* BFD status */
|
||||
switch (bs->ses_state) {
|
||||
@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
|
||||
}
|
||||
|
||||
/* BFD source prefix information. */
|
||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||
_ptm_msg_address(msg, &bs->mhop.local);
|
||||
} else {
|
||||
if (bs->local_address.sa_sin.sin_family)
|
||||
_ptm_msg_address(msg, &bs->local_address);
|
||||
else if (bs->local_address.sa_sin.sin_family)
|
||||
_ptm_msg_address(msg, &bs->local_ip);
|
||||
else {
|
||||
sac = bs->shop.peer;
|
||||
switch (sac.sa_sin.sin_family) {
|
||||
case AF_INET:
|
||||
memset(&sac.sa_sin.sin_addr, 0,
|
||||
sizeof(sac.sa_sin.sin_family));
|
||||
break;
|
||||
case AF_INET6:
|
||||
memset(&sac.sa_sin6.sin6_addr, 0,
|
||||
sizeof(sac.sa_sin6.sin6_family));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* No local address found yet, so send zeroes. */
|
||||
_ptm_msg_address(msg, &sac);
|
||||
}
|
||||
}
|
||||
_ptm_msg_address(msg, bs->key.family, &bs->key.local);
|
||||
|
||||
/* Write packet size. */
|
||||
stream_putw_at(msg, 0, stream_get_endp(msg));
|
||||
@ -290,7 +259,6 @@ stream_failure:
|
||||
static int _ptm_msg_read(struct stream *msg, int command,
|
||||
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
|
||||
{
|
||||
struct interface *ifp;
|
||||
uint32_t pid;
|
||||
uint8_t ttl __attribute__((unused));
|
||||
size_t ifnamelen;
|
||||
@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command,
|
||||
if (bpc->bpc_has_localif) {
|
||||
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
|
||||
bpc->bpc_localif[ifnamelen] = 0;
|
||||
|
||||
/*
|
||||
* IPv6 link-local addresses must use scope id,
|
||||
* otherwise the session lookup will always fail
|
||||
* and we'll have multiple sessions showing up.
|
||||
*
|
||||
* This problem only happens with single hop
|
||||
* since it is not possible to have link-local
|
||||
* address for multi hop sessions.
|
||||
*/
|
||||
if (bpc->bpc_ipv4 == false
|
||||
&& IN6_IS_ADDR_LINKLOCAL(
|
||||
&bpc->bpc_peer.sa_sin6.sin6_addr)) {
|
||||
ifp = if_lookup_by_name_all_vrf(
|
||||
bpc->bpc_localif);
|
||||
if (ifp == NULL) {
|
||||
log_error(
|
||||
"ptm-read: interface %s doesn't exists",
|
||||
bpc->bpc_localif);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpc->bpc_peer.sa_sin6.sin6_scope_id =
|
||||
ifp->ifindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
|
||||
|
||||
/* Interface name mismatch. */
|
||||
bs = bso->bso_bs;
|
||||
if (strcmp(ifp->name, bs->ifname))
|
||||
if (strcmp(ifp->name, bs->key.ifname))
|
||||
continue;
|
||||
/* Skip enabled sessions. */
|
||||
if (bs->sock != -1)
|
||||
@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
|
||||
|
||||
/* Interface name mismatch. */
|
||||
bs = bso->bso_bs;
|
||||
if (strcmp(ifp->name, bs->ifname))
|
||||
if (strcmp(ifp->name, bs->key.ifname))
|
||||
continue;
|
||||
/* Skip disabled sessions. */
|
||||
if (bs->sock == -1)
|
||||
@ -691,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bfdd_sessions_enable_address(struct connected *ifc)
|
||||
{
|
||||
struct bfd_session_observer *bso;
|
||||
struct bfd_session *bs;
|
||||
struct prefix prefix;
|
||||
|
||||
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
|
||||
if (bso->bso_isaddress == false)
|
||||
continue;
|
||||
|
||||
/* Skip enabled sessions. */
|
||||
bs = bso->bso_bs;
|
||||
if (bs->sock != -1)
|
||||
continue;
|
||||
|
||||
/* Check address. */
|
||||
prefix = bso->bso_addr;
|
||||
prefix.prefixlen = ifc->address->prefixlen;
|
||||
if (prefix_cmp(&prefix, ifc->address))
|
||||
continue;
|
||||
|
||||
/* Try to enable it. */
|
||||
bfd_session_enable(bs);
|
||||
}
|
||||
}
|
||||
|
||||
static int bfdd_interface_address_update(int cmd, struct zclient *zc,
|
||||
zebra_size_t len
|
||||
__attribute__((__unused__)),
|
||||
vrf_id_t vrfid)
|
||||
{
|
||||
struct connected *ifc;
|
||||
|
||||
ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid);
|
||||
if (ifc == NULL)
|
||||
return 0;
|
||||
|
||||
bfdd_sessions_enable_address(ifc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
|
||||
{
|
||||
zclient = zclient_new(master, &zclient_options_default);
|
||||
@ -713,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
|
||||
|
||||
/* Learn about interface VRF. */
|
||||
zclient->interface_vrf_update = bfdd_interface_vrf_update;
|
||||
|
||||
/* Learn about new addresses being registered. */
|
||||
zclient->interface_address_add = bfdd_interface_address_update;
|
||||
zclient->interface_address_delete = bfdd_interface_address_update;
|
||||
}
|
||||
|
||||
void bfdd_zclient_stop(void)
|
||||
|
@ -384,7 +384,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
|
||||
}
|
||||
}
|
||||
|
||||
zlog_info("Resetting peer %s%s due to change in addpath config\n",
|
||||
zlog_info("Resetting peer %s%s due to change in addpath config",
|
||||
CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
|
||||
peer->host);
|
||||
|
||||
|
@ -1715,7 +1715,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
||||
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
|
||||
if (!peer->nexthop.ifp) {
|
||||
zlog_warn("%s: interface not set appropriately to handle some attributes",
|
||||
zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing",
|
||||
peer->host);
|
||||
return BGP_ATTR_PARSE_WITHDRAW;
|
||||
}
|
||||
@ -1732,7 +1732,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
||||
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
|
||||
if (!peer->nexthop.ifp) {
|
||||
zlog_warn("%s: interface not set appropriately to handle some attributes",
|
||||
zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing",
|
||||
peer->host);
|
||||
return BGP_ATTR_PARSE_WITHDRAW;
|
||||
}
|
||||
@ -1762,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
||||
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
|
||||
}
|
||||
if (!peer->nexthop.ifp) {
|
||||
zlog_warn("%s: Interface not set appropriately to handle this some attributes",
|
||||
zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing",
|
||||
peer->host);
|
||||
return BGP_ATTR_PARSE_WITHDRAW;
|
||||
}
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "bgpd/bgp_zebra.h"
|
||||
#include "bgpd/bgp_nexthop.h"
|
||||
#include "bgpd/bgp_addpath.h"
|
||||
#include "bgpd/bgp_mac.h"
|
||||
|
||||
/*
|
||||
* Definitions and external declarations.
|
||||
@ -2503,6 +2504,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
/* Perform route selection and update zebra, if required. */
|
||||
bgp_process(bgp_vrf, rn, afi, safi);
|
||||
|
||||
/* Process for route leaking. */
|
||||
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2668,6 +2672,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
if (!pi)
|
||||
return 0;
|
||||
|
||||
/* Process for route leaking. */
|
||||
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
|
||||
|
||||
bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
|
||||
|
||||
/* Mark entry for deletion */
|
||||
@ -2940,6 +2947,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This API will scan evpn routes for checking attribute's rmac
|
||||
* macthes with bgp instance router mac. It avoid installing
|
||||
* route into bgp vrf table and remote rmac in bridge table.
|
||||
*/
|
||||
static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
|
||||
struct prefix_evpn *evp,
|
||||
struct bgp_path_info *pi)
|
||||
{
|
||||
/* evpn route could have learnt prior to L3vni has come up,
|
||||
* perform rmac check before installing route and
|
||||
* remote router mac.
|
||||
* The route will be removed from global bgp table once
|
||||
* SVI comes up with MAC and stored in hash, triggers
|
||||
* bgp_mac_rescan_all_evpn_tables.
|
||||
*/
|
||||
if (pi->attr &&
|
||||
memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
|
||||
if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
|
||||
char buf1[PREFIX_STRLEN];
|
||||
char attr_str[BUFSIZ] = {0};
|
||||
|
||||
bgp_dump_attr(pi->attr, attr_str, BUFSIZ);
|
||||
|
||||
zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac",
|
||||
__func__, bgp_vrf->vrf_id,
|
||||
prefix2str(evp, buf1, sizeof(buf1)),
|
||||
attr_str);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install or uninstall mac-ip routes are appropriate for this
|
||||
* particular VRF.
|
||||
@ -2996,6 +3038,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
|
||||
continue;
|
||||
|
||||
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
|
||||
if (bgp_evpn_route_rmac_self_check(
|
||||
bgp_vrf, evp, pi))
|
||||
continue;
|
||||
|
||||
if (install)
|
||||
ret = install_evpn_route_entry_in_vrf(
|
||||
bgp_vrf, evp, pi);
|
||||
@ -4223,11 +4269,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
|
||||
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Only care about "selected" routes - non-imported. */
|
||||
/* Only care about "selected" routes. Also ensure that
|
||||
* these are routes that are injectable into EVPN.
|
||||
*/
|
||||
/* TODO: Support for AddPath for EVPN. */
|
||||
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
||||
&& (!pi->extra || !pi->extra->parent)) {
|
||||
&& is_route_injectable_into_evpn(pi)) {
|
||||
bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
|
||||
afi, safi);
|
||||
break;
|
||||
@ -4294,12 +4342,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Need to identify the "selected" route entry to use its
|
||||
* attribute. Also, we only consider "non-imported" routes.
|
||||
* attribute. Also, ensure that the route is injectable
|
||||
* into EVPN.
|
||||
* TODO: Support for AddPath for EVPN.
|
||||
*/
|
||||
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
||||
&& (!pi->extra || !pi->extra->parent)) {
|
||||
&& is_route_injectable_into_evpn(pi)) {
|
||||
|
||||
/* apply the route-map */
|
||||
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
|
||||
@ -5033,6 +5082,9 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
*/
|
||||
void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
|
||||
{
|
||||
if (is_vrf_rd_configured(bgp))
|
||||
return;
|
||||
|
||||
form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd);
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
|
||||
!ri->extra->parent)
|
||||
return 0;
|
||||
|
||||
/* See if the parent is of family L2VPN/EVPN */
|
||||
parent_ri = (struct bgp_path_info *)ri->extra->parent;
|
||||
/* Determine parent recursively */
|
||||
for (parent_ri = ri->extra->parent;
|
||||
parent_ri->extra && parent_ri->extra->parent;
|
||||
parent_ri = parent_ri->extra->parent)
|
||||
;
|
||||
|
||||
/* See if of family L2VPN/EVPN */
|
||||
rn = parent_ri->net;
|
||||
if (!rn)
|
||||
return 0;
|
||||
@ -102,6 +107,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Flag if the route path's family is EVPN. */
|
||||
static inline bool is_pi_family_evpn(struct bgp_path_info *pi)
|
||||
{
|
||||
return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN);
|
||||
}
|
||||
|
||||
/* Flag if the route is injectable into EVPN. This would be either a
|
||||
* non-imported route or a non-EVPN imported route.
|
||||
*/
|
||||
static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
|
||||
{
|
||||
struct bgp_path_info *parent_pi;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
|
||||
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
|
||||
!pi->extra ||
|
||||
!pi->extra->parent)
|
||||
return true;
|
||||
|
||||
parent_pi = (struct bgp_path_info *)pi->extra->parent;
|
||||
rn = parent_pi->net;
|
||||
if (!rn)
|
||||
return true;
|
||||
table = bgp_node_table(rn);
|
||||
if (table &&
|
||||
table->afi == AFI_L2VPN &&
|
||||
table->safi == SAFI_EVPN)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||
struct prefix *p,
|
||||
struct attr *src_attr, afi_t afi,
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
#define RT_ADDRSTRLEN 28
|
||||
|
||||
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
|
||||
#define EVPN_ROUTE_PREFIXLEN 224
|
||||
/* EVPN prefix lengths. This represents the sizeof struct evpn_addr
|
||||
* in bits */
|
||||
#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8)
|
||||
|
||||
/* EVPN route types. */
|
||||
typedef enum {
|
||||
|
@ -3369,7 +3369,8 @@ DEFUN (bgp_evpn_advertise_type5,
|
||||
}
|
||||
|
||||
/* advertise type-5 routes */
|
||||
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
|
||||
if (advertise_type5_routes(bgp_vrf, afi))
|
||||
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -5222,7 +5223,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
vty_out(vty, " default-originate ipv6\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
|
||||
vty_out(vty, " rd %s\n",
|
||||
vty_out(vty, " rd %s\n",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
|
||||
|
||||
/* import route-target */
|
||||
|
@ -310,7 +310,8 @@ void bgp_timer_set(struct peer *peer)
|
||||
status start timer is on unless peer is shutdown or peer is
|
||||
inactive. All other timer must be turned off */
|
||||
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
|
||||
|| peer->bgp->vrf_id == VRF_UNKNOWN) {
|
||||
|| (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
|
||||
peer->bgp->vrf_id == VRF_UNKNOWN)) {
|
||||
BGP_TIMER_OFF(peer->t_start);
|
||||
} else {
|
||||
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
|
||||
@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (peer->bgp->vrf_id == VRF_UNKNOWN) {
|
||||
if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
|
||||
peer->bgp->vrf_id == VRF_UNKNOWN) {
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
flog_err(
|
||||
EC_BGP_FSM,
|
||||
|
@ -284,9 +284,9 @@ static int bgp_vrf_enable(struct vrf *vrf)
|
||||
bgp_vrf_link(bgp, vrf);
|
||||
|
||||
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
|
||||
/* Update any redistribute vrf bitmaps if the vrf_id changed */
|
||||
/* Update any redistribution if vrf_id changed */
|
||||
if (old_vrf_id != bgp->vrf_id)
|
||||
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
|
||||
bgp_redistribute_redo(bgp);
|
||||
bgp_instance_up(bgp);
|
||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
|
||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
|
||||
@ -333,9 +333,9 @@ static int bgp_vrf_disable(struct vrf *vrf)
|
||||
/* We have instance configured, unlink from VRF and make it
|
||||
* "down". */
|
||||
bgp_vrf_unlink(bgp, vrf);
|
||||
/* Update any redistribute vrf bitmaps if the vrf_id changed */
|
||||
/* Delete any redistribute vrf bitmaps if the vrf_id changed */
|
||||
if (old_vrf_id != bgp->vrf_id)
|
||||
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
|
||||
bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id);
|
||||
bgp_instance_down(bgp);
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "bgpd/bgp_zebra.h"
|
||||
#include "bgpd/bgp_nexthop.h"
|
||||
#include "bgpd/bgp_nht.h"
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
||||
if (bpi->extra && bpi->extra->bgp_orig)
|
||||
bgp_nexthop = bpi->extra->bgp_orig;
|
||||
|
||||
/* No nexthop tracking for redistributed routes */
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
|
||||
/*
|
||||
* No nexthop tracking for redistributed routes or for
|
||||
* EVPN-imported routes that get leaked.
|
||||
*/
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
|
||||
is_pi_family_evpn(bpi_ultimate))
|
||||
nh_valid = 1;
|
||||
else
|
||||
/*
|
||||
@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
||||
* No nexthop tracking for redistributed routes because
|
||||
* their originating protocols will do the tracking and
|
||||
* withdraw those routes if the nexthops become unreachable
|
||||
* This also holds good for EVPN-imported routes that get
|
||||
* leaked.
|
||||
*/
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
|
||||
if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
|
||||
is_pi_family_evpn(bpi_ultimate))
|
||||
nh_valid = 1;
|
||||
else
|
||||
/*
|
||||
@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
|
||||
return;
|
||||
}
|
||||
|
||||
/* loop check - should not be an imported route. */
|
||||
if (path_vrf->extra && path_vrf->extra->bgp_orig)
|
||||
/* Is this route exportable into the VPN table? */
|
||||
if (!is_route_injectable_into_vpn(path_vrf))
|
||||
return;
|
||||
|
||||
|
||||
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
||||
if (debug)
|
||||
zlog_debug("%s: %s skipping: %s", __func__,
|
||||
@ -894,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
||||
path_vrf->type, path_vrf->sub_type);
|
||||
}
|
||||
|
||||
if (path_vrf->sub_type != BGP_ROUTE_NORMAL
|
||||
&& path_vrf->sub_type != BGP_ROUTE_STATIC
|
||||
&& path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) {
|
||||
|
||||
if (debug)
|
||||
zlog_debug("%s: wrong sub_type %d", __func__,
|
||||
path_vrf->sub_type);
|
||||
return;
|
||||
}
|
||||
if (!bgp_vpn)
|
||||
return;
|
||||
|
||||
@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is this route exportable into the VPN table? */
|
||||
if (!is_route_injectable_into_vpn(path_vrf))
|
||||
return;
|
||||
|
||||
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
||||
if (debug)
|
||||
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
||||
@ -995,7 +997,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
|
||||
== bgp_vrf) {
|
||||
/* delete route */
|
||||
if (debug)
|
||||
zlog_debug("%s: deleting it\n",
|
||||
zlog_debug("%s: deleting it",
|
||||
__func__);
|
||||
bgp_aggregate_decrement(bgp_vpn, &bn->p,
|
||||
bpi, afi, safi);
|
||||
@ -1352,7 +1354,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
|
||||
|
||||
for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
|
||||
bpi = bpi->next) {
|
||||
if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) {
|
||||
if (bpi->extra
|
||||
&& bpi->extra->bgp_orig != bgp_vrf
|
||||
&& bpi->extra->parent
|
||||
&& is_pi_family_vpn(bpi->extra->parent)) {
|
||||
|
||||
/* delete route */
|
||||
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
|
||||
|
@ -226,6 +226,39 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
|
||||
}
|
||||
}
|
||||
|
||||
/* Flag if the route is injectable into VPN. This would be either a
|
||||
* non-imported route or a non-VPN imported route.
|
||||
*/
|
||||
static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi)
|
||||
{
|
||||
struct bgp_path_info *parent_pi;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
|
||||
if (pi->sub_type != BGP_ROUTE_IMPORTED ||
|
||||
!pi->extra ||
|
||||
!pi->extra->parent)
|
||||
return true;
|
||||
|
||||
parent_pi = (struct bgp_path_info *)pi->extra->parent;
|
||||
rn = parent_pi->net;
|
||||
if (!rn)
|
||||
return true;
|
||||
table = bgp_node_table(rn);
|
||||
if (table &&
|
||||
(table->afi == AFI_IP || table->afi == AFI_IP6) &&
|
||||
table->safi == SAFI_MPLS_VPN)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Flag if the route path's family is VPN. */
|
||||
static inline bool is_pi_family_vpn(struct bgp_path_info *pi)
|
||||
{
|
||||
return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) ||
|
||||
is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN));
|
||||
}
|
||||
|
||||
extern void vpn_policy_routemap_event(const char *rmap_name);
|
||||
|
||||
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
|
||||
|
@ -2476,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
|
||||
/* advertise/withdraw type-5 routes */
|
||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||
if (advertise_type5_routes(bgp, afi) && new_select &&
|
||||
(!new_select->extra || !new_select->extra->parent)) {
|
||||
if (advertise_type5_routes(bgp, afi) &&
|
||||
new_select &&
|
||||
is_route_injectable_into_evpn(new_select)) {
|
||||
|
||||
/* apply the route-map */
|
||||
if (bgp->adv_cmd_rmap[afi][safi].map) {
|
||||
@ -2500,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
afi, safi);
|
||||
|
||||
}
|
||||
} else if (advertise_type5_routes(bgp, afi) && old_select &&
|
||||
(!old_select->extra || !old_select->extra->parent))
|
||||
} else if (advertise_type5_routes(bgp, afi) &&
|
||||
old_select &&
|
||||
is_route_injectable_into_evpn(old_select))
|
||||
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
||||
}
|
||||
|
||||
|
@ -409,6 +409,24 @@ static inline int bgp_fibupd_safi(safi_t safi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Flag if the route path's family matches params. */
|
||||
static inline bool is_pi_family_matching(struct bgp_path_info *pi,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
|
||||
rn = pi->net;
|
||||
if (!rn)
|
||||
return false;
|
||||
table = bgp_node_table(rn);
|
||||
if (table &&
|
||||
table->afi == afi &&
|
||||
table->safi == safi)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prototypes. */
|
||||
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
|
||||
struct peer *peer, afi_t afi, safi_t safi);
|
||||
|
@ -3368,7 +3368,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|
||||
"Processing route_map %s update on advertise type5 route command",
|
||||
rmap_name);
|
||||
|
||||
if (route_update) {
|
||||
if (route_update && advertise_type5_routes(bgp, afi)) {
|
||||
bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
|
||||
bgp_evpn_advertise_type5_routes(bgp, afi, safi);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
|
||||
static struct cache *find_cache(const uint8_t preference);
|
||||
static int add_tcp_cache(const char *host, const char *port,
|
||||
const uint8_t preference);
|
||||
static void print_record(const struct pfx_record *record, void *data);
|
||||
static void print_record(const struct pfx_record *record, struct vty *vty);
|
||||
static int is_synchronized(void);
|
||||
static int is_running(void);
|
||||
static void route_match_free(void *rule);
|
||||
@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void print_record(const struct pfx_record *record, void *data)
|
||||
static void print_record(const struct pfx_record *record, struct vty *vty)
|
||||
{
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
|
||||
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
|
||||
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
|
||||
record->max_len, record->asn);
|
||||
}
|
||||
|
||||
static void print_record_cb(const struct pfx_record *record, void *data)
|
||||
{
|
||||
struct rpki_for_each_record_arg *arg = data;
|
||||
struct vty *vty = arg->vty;
|
||||
|
||||
(*arg->prefix_amount)++;
|
||||
|
||||
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
|
||||
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
|
||||
record->max_len, record->asn);
|
||||
print_record(record, vty);
|
||||
}
|
||||
|
||||
static struct rtr_mgr_group *get_groups(void)
|
||||
@ -663,10 +669,10 @@ static void print_prefix_table(struct vty *vty)
|
||||
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
|
||||
|
||||
arg.prefix_amount = &number_of_ipv4_prefixes;
|
||||
pfx_table_for_each_ipv4_record(pfx_table, print_record, &arg);
|
||||
pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
|
||||
|
||||
arg.prefix_amount = &number_of_ipv6_prefixes;
|
||||
pfx_table_for_each_ipv6_record(pfx_table, print_record, &arg);
|
||||
pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
|
||||
|
||||
vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes);
|
||||
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
|
||||
@ -1179,6 +1185,58 @@ DEFUN (show_rpki_prefix_table,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (show_rpki_prefix,
|
||||
show_rpki_prefix_cmd,
|
||||
"show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]",
|
||||
SHOW_STR
|
||||
RPKI_OUTPUT_STRING
|
||||
"Lookup IP prefix and optionally ASN in prefix table\n"
|
||||
"IPv4 prefix\n"
|
||||
"IPv6 prefix\n"
|
||||
"AS Number\n")
|
||||
{
|
||||
|
||||
if (!is_synchronized()) {
|
||||
vty_out(vty, "No Conection to RPKI cache server.\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
struct lrtr_ip_addr addr;
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
size_t addr_len = strchr(prefix_str, '/') - prefix_str;
|
||||
|
||||
memset(addr_str, 0, sizeof(addr_str));
|
||||
memcpy(addr_str, prefix_str, addr_len);
|
||||
|
||||
if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
|
||||
vty_out(vty, "Invalid IP prefix\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
struct pfx_record *matches = NULL;
|
||||
unsigned int match_count = 0;
|
||||
enum pfxv_state result;
|
||||
|
||||
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
|
||||
asn, &addr, prefix->prefixlen, &result)
|
||||
!= PFX_SUCCESS) {
|
||||
vty_out(vty, "Prefix lookup failed");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
|
||||
for (size_t i = 0; i < match_count; ++i) {
|
||||
const struct pfx_record *record = &matches[i];
|
||||
|
||||
if (record->max_len >= prefix->prefixlen
|
||||
&& ((asn != 0 && asn == record->asn) || asn == 0)) {
|
||||
print_record(&matches[i], vty);
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_rpki_cache_server,
|
||||
show_rpki_cache_server_cmd,
|
||||
"show rpki cache-server",
|
||||
@ -1450,6 +1508,7 @@ static void install_cli_commands(void)
|
||||
install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd);
|
||||
install_element(ENABLE_NODE, &show_rpki_cache_connection_cmd);
|
||||
install_element(ENABLE_NODE, &show_rpki_cache_server_cmd);
|
||||
install_element(ENABLE_NODE, &show_rpki_prefix_cmd);
|
||||
|
||||
/* Install debug commands */
|
||||
install_element(CONFIG_NODE, &debug_rpki_cmd);
|
||||
|
197
bgpd/bgp_vty.c
197
bgpd/bgp_vty.c
@ -2055,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void bgp_redistribute_redo(struct bgp *bgp)
|
||||
{
|
||||
afi_t afi;
|
||||
int i;
|
||||
struct list *red_list;
|
||||
struct listnode *node;
|
||||
struct bgp_redist *red;
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
|
||||
red_list = bgp->redist[afi][i];
|
||||
if (!red_list)
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
|
||||
bgp_redistribute_resend(bgp, afi, i,
|
||||
red->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* "bgp graceful-shutdown" configuration */
|
||||
DEFUN (bgp_graceful_shutdown,
|
||||
bgp_graceful_shutdown_cmd,
|
||||
@ -2841,18 +2818,23 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
|
||||
as = strtoul(as_str, NULL, 10);
|
||||
}
|
||||
|
||||
/* If peer is peer group, call proper function. */
|
||||
/* If peer is peer group or interface peer, call proper function. */
|
||||
ret = str2sockunion(peer_str, &su);
|
||||
if (ret < 0) {
|
||||
/* Check for peer by interface */
|
||||
struct peer *peer;
|
||||
|
||||
/* Check if existing interface peer */
|
||||
peer = peer_lookup_by_conf_if(bgp, peer_str);
|
||||
|
||||
ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi,
|
||||
safi);
|
||||
if (ret < 0) {
|
||||
|
||||
/* if not interface peer, check peer-group settings */
|
||||
if (ret < 0 && !peer) {
|
||||
ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
|
||||
if (ret < 0) {
|
||||
vty_out(vty,
|
||||
"%% Create the peer-group or interface first or specify \"interface\" keyword\n");
|
||||
vty_out(vty, "%% if using an unnumbered interface neighbor\n");
|
||||
"%% Create the peer-group or interface first\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
@ -3251,7 +3233,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
|
||||
/* look up for neighbor by interface name config. */
|
||||
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
|
||||
if (peer) {
|
||||
peer_as_change(peer, 0, AS_SPECIFIED);
|
||||
peer_as_change(peer, 0, AS_UNSPECIFIED);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -8031,7 +8013,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
|
||||
json, "ribMemory",
|
||||
ents * sizeof(struct bgp_node));
|
||||
|
||||
ents = listcount(bgp->peer);
|
||||
ents = bgp->af_peer_count[afi][safi];
|
||||
json_object_int_add(json, "peerCount", ents);
|
||||
json_object_int_add(json, "peerMemory",
|
||||
ents * sizeof(struct peer));
|
||||
@ -8071,7 +8053,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
|
||||
bgp_node)));
|
||||
|
||||
/* Peer related usage */
|
||||
ents = listcount(bgp->peer);
|
||||
ents = bgp->af_peer_count[afi][safi];
|
||||
vty_out(vty, "Peers %ld, using %s of memory\n",
|
||||
ents,
|
||||
mtype_memstr(
|
||||
@ -8522,7 +8504,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi)
|
||||
}
|
||||
|
||||
/* Show BGP peer's information. */
|
||||
enum show_type { show_all, show_peer };
|
||||
enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
|
||||
|
||||
static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
|
||||
afi_t afi, safi_t safi,
|
||||
@ -10945,6 +10927,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
|
||||
struct peer *peer;
|
||||
int find = 0;
|
||||
bool nbr_output = false;
|
||||
afi_t afi = AFI_MAX;
|
||||
safi_t safi = SAFI_MAX;
|
||||
|
||||
if (type == show_ipv4_peer || type == show_ipv4_all) {
|
||||
afi = AFI_IP;
|
||||
} else if (type == show_ipv6_peer || type == show_ipv6_all) {
|
||||
afi = AFI_IP6;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
|
||||
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
|
||||
@ -10973,17 +10963,54 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case show_ipv4_peer:
|
||||
case show_ipv6_peer:
|
||||
FOREACH_SAFI (safi) {
|
||||
if (peer->afc[afi][safi]) {
|
||||
if (conf_if) {
|
||||
if ((peer->conf_if
|
||||
&& !strcmp(peer->conf_if, conf_if))
|
||||
|| (peer->hostname
|
||||
&& !strcmp(peer->hostname, conf_if))) {
|
||||
find = 1;
|
||||
bgp_show_peer(vty, peer, use_json,
|
||||
json);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (sockunion_same(&peer->su, su)) {
|
||||
find = 1;
|
||||
bgp_show_peer(vty, peer, use_json,
|
||||
json);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case show_ipv4_all:
|
||||
case show_ipv6_all:
|
||||
FOREACH_SAFI (safi) {
|
||||
if (peer->afc[afi][safi]) {
|
||||
bgp_show_peer(vty, peer, use_json, json);
|
||||
nbr_output = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == show_peer && !find) {
|
||||
if ((type == show_peer || type == show_ipv4_peer ||
|
||||
type == show_ipv6_peer) && !find) {
|
||||
if (use_json)
|
||||
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
|
||||
else
|
||||
vty_out(vty, "%% No such neighbor in this view/vrf\n");
|
||||
}
|
||||
|
||||
if (type != show_peer && !nbr_output && !use_json)
|
||||
if (type != show_peer && type != show_ipv4_peer &&
|
||||
type != show_ipv6_peer && !nbr_output && !use_json)
|
||||
vty_out(vty, "%% No BGP neighbors found\n");
|
||||
|
||||
if (use_json) {
|
||||
@ -11049,7 +11076,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
|
||||
: bgp->name);
|
||||
}
|
||||
|
||||
if (type == show_peer) {
|
||||
if (type == show_peer || type == show_ipv4_peer ||
|
||||
type == show_ipv6_peer) {
|
||||
ret = str2sockunion(ip_str, &su);
|
||||
if (ret < 0)
|
||||
bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
|
||||
@ -11058,7 +11086,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
|
||||
bgp_show_neighbor(vty, bgp, type, &su, NULL,
|
||||
use_json, json);
|
||||
} else {
|
||||
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
|
||||
bgp_show_neighbor(vty, bgp, type, NULL, NULL,
|
||||
use_json, json);
|
||||
}
|
||||
json_object_free(json);
|
||||
@ -11151,6 +11179,7 @@ DEFUN (show_ip_bgp_neighbors,
|
||||
char *vrf = NULL;
|
||||
char *sh_arg = NULL;
|
||||
enum show_type sh_type;
|
||||
afi_t afi = AFI_MAX;
|
||||
|
||||
bool uj = use_json(argc, argv);
|
||||
|
||||
@ -11166,13 +11195,29 @@ DEFUN (show_ip_bgp_neighbors,
|
||||
vrf = argv[idx + 1]->arg;
|
||||
|
||||
idx++;
|
||||
|
||||
if (argv_find(argv, argc, "ipv4", &idx)) {
|
||||
sh_type = show_ipv4_all;
|
||||
afi = AFI_IP;
|
||||
} else if (argv_find(argv, argc, "ipv6", &idx)) {
|
||||
sh_type = show_ipv6_all;
|
||||
afi = AFI_IP6;
|
||||
} else {
|
||||
sh_type = show_all;
|
||||
}
|
||||
|
||||
if (argv_find(argv, argc, "A.B.C.D", &idx)
|
||||
|| argv_find(argv, argc, "X:X::X:X", &idx)
|
||||
|| argv_find(argv, argc, "WORD", &idx)) {
|
||||
sh_type = show_peer;
|
||||
sh_arg = argv[idx]->arg;
|
||||
} else
|
||||
sh_type = show_all;
|
||||
}
|
||||
|
||||
if (sh_type == show_peer && afi == AFI_IP) {
|
||||
sh_type = show_ipv4_peer;
|
||||
} else if (sh_type == show_peer && afi == AFI_IP6) {
|
||||
sh_type = show_ipv6_peer;
|
||||
}
|
||||
|
||||
return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj);
|
||||
}
|
||||
@ -11267,8 +11312,9 @@ DEFUN (show_ip_bgp_attr_info,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
safi_t safi, bool use_json)
|
||||
static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
|
||||
afi_t afi, safi_t safi,
|
||||
bool use_json, json_object *json)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
struct listnode *node;
|
||||
@ -11277,13 +11323,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
char *ecom_str;
|
||||
vpn_policy_direction_t dir;
|
||||
|
||||
if (use_json) {
|
||||
json_object *json = NULL;
|
||||
if (json) {
|
||||
json_object *json_import_vrfs = NULL;
|
||||
json_object *json_export_vrfs = NULL;
|
||||
|
||||
json = json_object_new_object();
|
||||
|
||||
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
|
||||
|
||||
if (!bgp) {
|
||||
@ -11354,11 +11397,12 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(json,
|
||||
if (use_json) {
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(json,
|
||||
JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
|
||||
json_object_free(json);
|
||||
}
|
||||
} else {
|
||||
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
|
||||
|
||||
@ -11422,6 +11466,54 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
|
||||
safi_t safi, bool use_json)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct bgp *bgp;
|
||||
char *vrf_name = NULL;
|
||||
json_object *json = NULL;
|
||||
json_object *json_vrf = NULL;
|
||||
json_object *json_vrfs = NULL;
|
||||
|
||||
if (use_json) {
|
||||
json = json_object_new_object();
|
||||
json_vrfs = json_object_new_object();
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
|
||||
|
||||
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
|
||||
vrf_name = bgp->name;
|
||||
|
||||
if (use_json) {
|
||||
json_vrf = json_object_new_object();
|
||||
} else {
|
||||
vty_out(vty, "\nInstance %s:\n",
|
||||
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||
? VRF_DEFAULT_NAME : bgp->name);
|
||||
}
|
||||
bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf);
|
||||
if (use_json) {
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||
json_object_object_add(json_vrfs,
|
||||
VRF_DEFAULT_NAME, json_vrf);
|
||||
else
|
||||
json_object_object_add(json_vrfs, vrf_name,
|
||||
json_vrf);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_json) {
|
||||
json_object_object_add(json, "vrfs", json_vrfs);
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
|
||||
JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* "show [ip] bgp route-leak" command. */
|
||||
DEFUN (show_ip_bgp_route_leak,
|
||||
show_ip_bgp_route_leak_cmd,
|
||||
@ -11441,6 +11533,7 @@ DEFUN (show_ip_bgp_route_leak,
|
||||
|
||||
bool uj = use_json(argc, argv);
|
||||
int idx = 0;
|
||||
json_object *json = NULL;
|
||||
|
||||
/* show [ip] bgp */
|
||||
if (argv_find(argv, argc, "ip", &idx)) {
|
||||
@ -11470,7 +11563,13 @@ DEFUN (show_ip_bgp_route_leak,
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj);
|
||||
if (vrf && strmatch(vrf, "all"))
|
||||
return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj);
|
||||
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json);
|
||||
}
|
||||
|
||||
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
|
||||
|
@ -1819,23 +1819,42 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Update redistribute vrf bitmap during triggers like
|
||||
restart networking or delete/add VRFs */
|
||||
void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
|
||||
void bgp_redistribute_redo(struct bgp *bgp)
|
||||
{
|
||||
afi_t afi;
|
||||
int i;
|
||||
struct list *red_list;
|
||||
struct listnode *node;
|
||||
struct bgp_redist *red;
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
|
||||
red_list = bgp->redist[afi][i];
|
||||
if (!red_list)
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
|
||||
bgp_redistribute_resend(bgp, afi, i,
|
||||
red->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unset redistribute vrf bitmap during triggers like
|
||||
restart networking or delete VRFs */
|
||||
void bgp_unset_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
|
||||
{
|
||||
int i;
|
||||
afi_t afi;
|
||||
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
||||
if ((old_vrf_id == VRF_UNKNOWN)
|
||||
|| vrf_bitmap_check(zclient->redist[afi][i],
|
||||
old_vrf_id)) {
|
||||
if (vrf_bitmap_check(zclient->redist[afi][i],
|
||||
old_vrf_id))
|
||||
vrf_bitmap_unset(zclient->redist[afi][i],
|
||||
old_vrf_id);
|
||||
vrf_bitmap_set(zclient->redist[afi][i],
|
||||
bgp->vrf_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer);
|
||||
extern void bgp_zebra_instance_register(struct bgp *);
|
||||
extern void bgp_zebra_instance_deregister(struct bgp *);
|
||||
|
||||
extern void bgp_redistribute_redo(struct bgp *bgp);
|
||||
extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t,
|
||||
unsigned short);
|
||||
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,
|
||||
|
11
bgpd/bgpd.c
11
bgpd/bgpd.c
@ -707,6 +707,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct peer_af *af;
|
||||
int afid;
|
||||
struct bgp *bgp;
|
||||
|
||||
if (!peer)
|
||||
return NULL;
|
||||
@ -715,6 +716,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
|
||||
if (afid >= BGP_AF_MAX)
|
||||
return NULL;
|
||||
|
||||
bgp = peer->bgp;
|
||||
assert(peer->peer_af_array[afid] == NULL);
|
||||
|
||||
/* Allocate new peer af */
|
||||
@ -725,6 +727,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
|
||||
af->safi = safi;
|
||||
af->afid = afid;
|
||||
af->peer = peer;
|
||||
bgp->af_peer_count[afi][safi]++;
|
||||
|
||||
return af;
|
||||
}
|
||||
@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct peer_af *af;
|
||||
int afid;
|
||||
struct bgp *bgp;
|
||||
|
||||
if (!peer)
|
||||
return -1;
|
||||
@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
|
||||
if (!af)
|
||||
return -1;
|
||||
|
||||
bgp = peer->bgp;
|
||||
bgp_stop_announce_route_timer(af);
|
||||
|
||||
if (PAF_SUBGRP(af)) {
|
||||
@ -768,8 +773,12 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
|
||||
af->subgroup->id, peer->host);
|
||||
}
|
||||
|
||||
|
||||
update_subgroup_remove_peer(af->subgroup, af);
|
||||
|
||||
if (bgp->af_peer_count[afi][safi])
|
||||
bgp->af_peer_count[afi][safi]--;
|
||||
|
||||
peer->peer_af_array[afid] = NULL;
|
||||
XFREE(MTYPE_BGP_PEER_AF, af);
|
||||
return 0;
|
||||
@ -2714,7 +2723,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
|
||||
peer->sort = group->conf->sort;
|
||||
}
|
||||
|
||||
if (!group->conf->as) {
|
||||
if (!group->conf->as && peer_sort(peer)) {
|
||||
if (peer_sort(group->conf) != BGP_PEER_INTERNAL
|
||||
&& peer_sort(group->conf) != peer_sort(peer)) {
|
||||
if (as)
|
||||
|
@ -99,6 +99,9 @@ enum bgp_af_index {
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) \
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
|
||||
|
||||
#define FOREACH_SAFI(safi) \
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
|
||||
|
||||
extern struct frr_pthread *bgp_pth_io;
|
||||
extern struct frr_pthread *bgp_pth_ka;
|
||||
|
||||
@ -377,6 +380,9 @@ struct bgp {
|
||||
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7)
|
||||
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8)
|
||||
|
||||
/* BGP per AF peer count */
|
||||
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
|
||||
|
||||
/* Route table for next-hop lookup cache. */
|
||||
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
||||
|
||||
@ -1906,7 +1912,7 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf)
|
||||
bgp->vrf_id = VRF_UNKNOWN;
|
||||
}
|
||||
|
||||
extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
|
||||
extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
|
||||
|
||||
/* For benefit of rfapi */
|
||||
extern struct peer *peer_new(struct bgp *bgp);
|
||||
|
@ -765,7 +765,7 @@ AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for con
|
||||
enable_logfile_mask=${enable_logfile_mask:-0600}
|
||||
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
|
||||
|
||||
MPATH_NUM=1
|
||||
MPATH_NUM=16
|
||||
|
||||
case "${enable_multipath}" in
|
||||
0)
|
||||
|
@ -1,9 +1,10 @@
|
||||
.. _building-centos6:
|
||||
|
||||
CentOS 6
|
||||
========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
This document describes installation from source. If you want to build an RPM,
|
||||
see :ref:`packaging-redhat`.
|
||||
|
||||
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
|
||||
|
||||
@ -24,7 +25,7 @@ CentOS 6 restrictions:
|
||||
PIMd is needed
|
||||
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
|
||||
or higher (LDP can be built, but may have limited use without MPLS)
|
||||
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
||||
- Zebra is unable to detect what bridge/vrf an interface is associated
|
||||
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
|
||||
you can use a newer kernel + headers to get this functionality)
|
||||
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
|
||||
@ -235,7 +236,7 @@ settings)::
|
||||
# Controls source route verification
|
||||
net.ipv4.conf.default.rp_filter = 0
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
Load the modified sysctl's on the system:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
CentOS 7
|
||||
========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
This document describes installation from source. If you want to build an RPM,
|
||||
see :ref:`packaging-redhat`.
|
||||
|
||||
CentOS 7 restrictions:
|
||||
----------------------
|
||||
@ -127,7 +126,7 @@ following content:
|
||||
net.ipv4.conf.all.forwarding=1
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
Load the modified sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
|
122
doc/developer/building-frr-for-fedora.rst
Normal file
122
doc/developer/building-frr-for-fedora.rst
Normal 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
|
@ -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
|
@ -11,7 +11,7 @@ FreeBSD 10 restrictions:
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
Add packages: (Allow the install of the package management tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
@ -11,7 +11,7 @@ FreeBSD 11 restrictions:
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
Add packages: (Allow the install of the package management tool if this
|
||||
is first package install and asked)
|
||||
|
||||
.. code-block:: shell
|
||||
|
@ -11,7 +11,7 @@ FreeBSD 9 restrictions:
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
Add packages: (Allow the install of the package management tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
@ -63,10 +63,10 @@ Usage
|
||||
-----
|
||||
|
||||
Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
|
||||
``DAEMONS=`` or don't install unneded packages For example: zebra bgpd ldpd
|
||||
``DAEMONS=`` or don't install unneeded packages For example: zebra bgpd ldpd
|
||||
isisd nhrpd ospfd ospf6d pimd ripd ripngd
|
||||
|
||||
Enable the serivce
|
||||
Enable the service
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- ``service frr enable``
|
||||
|
@ -1,35 +1,30 @@
|
||||
Ubuntu 14.04LTS
|
||||
===============================================
|
||||
Ubuntu 14.04 LTS
|
||||
================
|
||||
|
||||
- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
This document describes installation from source. If you want to build a
|
||||
``deb``, see :ref:`packaging-debian`.
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
Installing Dependencies
|
||||
-----------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
apt-get update
|
||||
apt-get install \
|
||||
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
||||
dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||
libc-ares-dev python3-dev python3-sphinx install-info build-essential
|
||||
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||
libc-ares-dev python3-dev python3-sphinx install-info build-essential \
|
||||
libsnmp-dev perl
|
||||
|
||||
.. include:: building-libyang.rst
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
Building & Installing FRR
|
||||
-------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
Add frr groups and user
|
||||
Add FRR user and groups
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo groupadd -r -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
@ -37,102 +32,104 @@ Add frr groups and user
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
Download Source, configure and compile it
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Compile
|
||||
^^^^^^^
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
.. include:: include-compile.rst
|
||||
|
||||
Install FRR configuration files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo install -m 775 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
|
||||
|
||||
Tweak sysctls
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
|
||||
MPLS (if supported by your platform). If your platform does not support MPLS,
|
||||
skip the MPLS related configuration in this section.
|
||||
|
||||
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
other settings):
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
./configure \
|
||||
--prefix=/usr \
|
||||
--enable-exampledir=/usr/share/doc/frr/examples/ \
|
||||
--localstatedir=/var/run/frr \
|
||||
--sbindir=/usr/lib/frr \
|
||||
--sysconfdir=/etc/frr \
|
||||
--enable-multipath=64 \
|
||||
--enable-user=frr \
|
||||
--enable-group=frr \
|
||||
--enable-vty-group=frrvty \
|
||||
--enable-configfile-mask=0640 \
|
||||
--enable-logfile-mask=0640 \
|
||||
--enable-fpm \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check
|
||||
sudo make install
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
Create empty FRR configuration files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
# Uncomment the next line to enable packet forwarding for IPv6
|
||||
# Enabling this option disables Stateless Address Autoconfiguration
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||
|
||||
Add MPLS kernel modules
|
||||
"""""""""""""""""""""""
|
||||
|
||||
.. warning::
|
||||
|
||||
MPLS is not supported on Ubuntu 14.04 with the default kernel. MPLS requires
|
||||
kernel 4.5 or higher. LDPD can be built, but may have limited use without
|
||||
MPLS. For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
|
||||
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
|
||||
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
# Load MPLS Kernel Modules
|
||||
mpls_router
|
||||
mpls_iptunnel
|
||||
|
||||
Enable IP & IPv6 forwarding
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
And load the kernel modules on the running system:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo modprobe mpls-router mpls-iptunnel
|
||||
|
||||
Enable MPLS Forwarding
|
||||
""""""""""""""""""""""
|
||||
|
||||
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
|
||||
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv6
|
||||
# Enabling this option disables Stateless Address Autoconfiguration
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
# Enable MPLS Label processing on all interfaces
|
||||
net.mpls.conf.eth0.input=1
|
||||
net.mpls.conf.eth1.input=1
|
||||
net.mpls.conf.eth2.input=1
|
||||
net.mpls.platform_labels=100000
|
||||
|
||||
Install the init.d service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo install -m 755 tools/frr /etc/init.d/frr
|
||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
sudo install -m 755 tools/frr /etc/init.d/frr
|
||||
|
||||
Enable daemons
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||
those daemons you want to start by systemd.
|
||||
| For example.
|
||||
|
||||
::
|
||||
|
||||
zebra=yes
|
||||
bgpd=yes
|
||||
ospfd=yes
|
||||
ospf6d=yes
|
||||
ripd=yes
|
||||
ripngd=yes
|
||||
isisd=yes
|
||||
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
|
||||
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
|
||||
as required by changing the value to ``yes``.
|
||||
|
||||
Start the init.d service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- /etc/init.d/frr start
|
||||
- use ``/etc/init.d/frr status`` to check its status.
|
||||
.. code-block:: console
|
||||
|
||||
/etc/init.d/frr start
|
||||
|
||||
Use ``/etc/init.d/frr status`` to check its status.
|
||||
|
@ -1,172 +1,134 @@
|
||||
Ubuntu 16.04LTS
|
||||
===============================================
|
||||
Ubuntu 16.04 LTS
|
||||
================
|
||||
|
||||
- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
This document describes installation from source. If you want to build a
|
||||
``deb``, see :ref:`packaging-debian`.
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
Installing Dependencies
|
||||
-----------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
apt-get update
|
||||
apt-get install \
|
||||
git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \
|
||||
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
||||
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
|
||||
python3-sphinx install-info build-essential libsystemd-dev
|
||||
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
|
||||
install-info build-essential libsystemd-dev libsnmp-dev perl
|
||||
|
||||
.. include:: building-libyang.rst
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
Building & Installing FRR
|
||||
-------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
Add frr groups and user
|
||||
Add FRR user and groups
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo groupadd -r -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
sudo adduser --system --ingroup frr --home /var/run/frr/ \
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
sudo groupadd -r -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
sudo adduser --system --ingroup frr --home /var/run/frr/ \
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
Download Source, configure and compile it
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Compile
|
||||
^^^^^^^
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
.. include:: include-compile.rst
|
||||
|
||||
Install FRR configuration files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo install -m 775 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
|
||||
|
||||
Tweak sysctls
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
|
||||
MPLS (if supported by your platform). If your platform does not support MPLS,
|
||||
skip the MPLS related configuration in this section.
|
||||
|
||||
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
other settings):
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
./configure \
|
||||
--prefix=/usr \
|
||||
--enable-exampledir=/usr/share/doc/frr/examples/ \
|
||||
--localstatedir=/var/run/frr \
|
||||
--sbindir=/usr/lib/frr \
|
||||
--sysconfdir=/etc/frr \
|
||||
--enable-multipath=64 \
|
||||
--enable-user=frr \
|
||||
--enable-group=frr \
|
||||
--enable-vty-group=frrvty \
|
||||
--enable-configfile-mask=0640 \
|
||||
--enable-logfile-mask=0640 \
|
||||
--enable-fpm \
|
||||
--enable-systemd=yes \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check
|
||||
sudo make install
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
Create empty FRR configuration files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
# Uncomment the next line to enable packet forwarding for IPv6
|
||||
# Enabling this option disables Stateless Address Autoconfiguration
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
Enable IPv4 & IPv6 forwarding
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv6
|
||||
# Enabling this option disables Stateless Address Autoconfiguration
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
Enable MPLS Forwarding (with Linux Kernel >= 4.5)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
|
||||
line equal to ``net.mpls.conf.eth0.input`` or each interface used with
|
||||
MPLS
|
||||
|
||||
::
|
||||
|
||||
# Enable MPLS Label processing on all interfaces
|
||||
net.mpls.conf.eth0.input=1
|
||||
net.mpls.conf.eth1.input=1
|
||||
net.mpls.conf.eth2.input=1
|
||||
net.mpls.platform_labels=100000
|
||||
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||
|
||||
Add MPLS kernel modules
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
"""""""""""""""""""""""
|
||||
|
||||
Add the following lines to ``/etc/modules-load.d/modules.conf``:
|
||||
.. warning::
|
||||
|
||||
MPLS is not supported on Ubuntu 16.04 with the default kernel. MPLS requires
|
||||
kernel 4.5 or higher. LDPD can be built, but may have limited use without
|
||||
MPLS. For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
|
||||
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
|
||||
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
|
||||
|
||||
::
|
||||
|
||||
# Load MPLS Kernel Modules
|
||||
mpls-router
|
||||
mpls-iptunnel
|
||||
# Load MPLS Kernel Modules
|
||||
mpls_router
|
||||
mpls_iptunnel
|
||||
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
Install the systemd service (if rebooted from last step, change directory back to frr directory)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
And load the kernel modules on the running system:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo modprobe mpls-router mpls-iptunnel
|
||||
|
||||
Enable MPLS Forwarding
|
||||
""""""""""""""""""""""
|
||||
|
||||
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
|
||||
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
|
||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
||||
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
# Enable MPLS Label processing on all interfaces
|
||||
net.mpls.conf.eth0.input=1
|
||||
net.mpls.conf.eth1.input=1
|
||||
net.mpls.conf.eth2.input=1
|
||||
net.mpls.platform_labels=100000
|
||||
|
||||
Install service files
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
|
||||
sudo systemctl enable frr
|
||||
|
||||
Enable daemons
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||
those daemons you want to start by systemd.
|
||||
| For example.
|
||||
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
|
||||
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
|
||||
as required by changing the value to ``yes``.
|
||||
|
||||
::
|
||||
Start FRR
|
||||
^^^^^^^^^
|
||||
|
||||
zebra=yes
|
||||
bgpd=yes
|
||||
ospfd=yes
|
||||
ospf6d=yes
|
||||
ripd=yes
|
||||
ripngd=yes
|
||||
isisd=yes
|
||||
.. code-block:: console
|
||||
|
||||
Enable the systemd service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- systemctl enable frr
|
||||
|
||||
Start the systemd service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- systemctl start frr
|
||||
- use ``systemctl status frr`` to check its status.
|
||||
systemctl start frr
|
||||
|
@ -1,55 +1,44 @@
|
||||
Ubuntu 18.04 LTS
|
||||
================
|
||||
|
||||
Install dependencies
|
||||
--------------------
|
||||
This document describes installation from source. If you want to build a
|
||||
``deb``, see :ref:`packaging-debian`.
|
||||
|
||||
Required packages
|
||||
^^^^^^^^^^^^^^^^^
|
||||
Installing Dependencies
|
||||
-----------------------
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo apt update
|
||||
sudo apt-get install \
|
||||
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
||||
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
|
||||
python3-sphinx install-info build-essential libsystemd-dev
|
||||
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
|
||||
install-info build-essential libsystemd-dev libsnmp-dev perl
|
||||
|
||||
.. include:: building-libyang.rst
|
||||
|
||||
Optional packages
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Dependencies for additional functionality can be installed as-desired.
|
||||
|
||||
Protobuf
|
||||
~~~~~~~~
|
||||
^^^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo apt-get install \
|
||||
protobuf-c-compiler \
|
||||
libprotobuf-c-dev
|
||||
sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
|
||||
|
||||
ZeroMQ
|
||||
~~~~~~
|
||||
^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo apt-get install \
|
||||
libzmq5 \
|
||||
libzmq3-dev
|
||||
sudo apt-get install libzmq5 libzmq3-dev
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
Building & Installing FRR
|
||||
-------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
Add frr groups and user
|
||||
Add FRR user and groups
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo groupadd -r -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
@ -57,104 +46,29 @@ Add frr groups and user
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
Download source
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
|
||||
Configure
|
||||
^^^^^^^^^
|
||||
Options below are provided as an example.
|
||||
|
||||
.. seealso:: *Installation* section of user guide
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
./configure \
|
||||
--prefix=/usr \
|
||||
--enable-exampledir=/usr/share/doc/frr/examples/ \
|
||||
--localstatedir=/var/run/frr \
|
||||
--sbindir=/usr/lib/frr \
|
||||
--sysconfdir=/etc/frr \
|
||||
--enable-multipath=64 \
|
||||
--enable-user=frr \
|
||||
--enable-group=frr \
|
||||
--enable-vty-group=frrvty \
|
||||
--enable-configfile-mask=0640 \
|
||||
--enable-logfile-mask=0640 \
|
||||
--enable-fpm \
|
||||
--enable-systemd=yes \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
|
||||
If optional packages were installed, the associated feature may now be
|
||||
enabled.
|
||||
|
||||
.. option:: --enable-protobuf
|
||||
|
||||
Enable support for protobuf transport
|
||||
|
||||
.. option:: --enable-zeromq
|
||||
|
||||
Enable support for ZeroMQ transport
|
||||
|
||||
Compile
|
||||
^^^^^^^
|
||||
|
||||
::
|
||||
.. include:: include-compile.rst
|
||||
|
||||
make
|
||||
make check
|
||||
sudo make install
|
||||
Install FRR configuration files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Create empty FRR configuration files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. code-block:: console
|
||||
|
||||
Although not strictly necessary, it's good practice to create empty
|
||||
configuration files _before_ starting FRR. This assures that the permissions
|
||||
are correct. If the files are not already present, FRR will create them.
|
||||
|
||||
It's also important to consider _which_ files to create. FRR supports writing
|
||||
configuration to a monolithic file, :file:`/etc/frr/frr.conf`.
|
||||
|
||||
.. seealso:: *VTYSH* section of user guide
|
||||
|
||||
The presence of :file:`/etc/frr/frr.conf` on startup implicitly configures FRR
|
||||
to ignore daemon-specific configuration files.
|
||||
|
||||
Daemon-specific configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
||||
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
|
||||
|
||||
Monolithic configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Tweak sysctls
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf
|
||||
|
||||
Enable IPv4 & IPv6 forwarding
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
|
||||
MPLS (if supported by your platform). If your platform does not support MPLS,
|
||||
skip the MPLS related configuration in this section.
|
||||
|
||||
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
other settings):
|
||||
@ -169,8 +83,10 @@ other settings):
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||
|
||||
Add MPLS kernel modules
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
"""""""""""""""""""""""
|
||||
|
||||
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
|
||||
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
|
||||
@ -181,10 +97,15 @@ enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
|
||||
mpls_router
|
||||
mpls_iptunnel
|
||||
|
||||
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||
|
||||
And load the kernel modules on the running system:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo modprobe mpls-router mpls-iptunnel
|
||||
|
||||
Enable MPLS Forwarding
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
""""""""""""""""""""""
|
||||
|
||||
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
|
||||
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
|
||||
@ -197,48 +118,24 @@ equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
|
||||
net.mpls.conf.eth2.input=1
|
||||
net.mpls.platform_labels=100000
|
||||
|
||||
Install the systemd service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Install service files
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
.. code-block:: console
|
||||
|
||||
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
|
||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
||||
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
sudo systemctl enable frr
|
||||
|
||||
Enable daemons
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those
|
||||
daemons you want to start by systemd. For example:
|
||||
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
|
||||
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
|
||||
as required by changing the value to ``yes``.
|
||||
|
||||
::
|
||||
|
||||
zebra=yes
|
||||
bgpd=yes
|
||||
ospfd=yes
|
||||
ospf6d=yes
|
||||
ripd=yes
|
||||
ripngd=yes
|
||||
isisd=yes
|
||||
|
||||
Enable the systemd service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Enabling the systemd service causes FRR to be started upon boot. To enable it,
|
||||
use the following command:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
systemctl enable frr
|
||||
|
||||
Start the systemd service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Start FRR
|
||||
^^^^^^^^^
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
systemctl start frr
|
||||
|
||||
After starting the service, you can use ``systemctl status frr`` to check its
|
||||
status.
|
||||
|
@ -1,57 +1,55 @@
|
||||
The libyang library can be installed from third-party packages available `here
|
||||
<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
|
||||
FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF
|
||||
support. Unfortunately, most distributions do not yet offer a ``libyang``
|
||||
package from their repositories. Therefore we offer two options to install this
|
||||
library.
|
||||
|
||||
Note: the libyang dev/devel packages need to be installed in addition
|
||||
to the libyang core package in order to build FRR successfully.
|
||||
**Option 1: Binary Install**
|
||||
|
||||
The FRR project builds binary ``libyang`` packages, which we offer for download
|
||||
`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
|
||||
|
||||
.. warning::
|
||||
libyang ABI version 0.16.74 or newer will be required to build FRR in the
|
||||
near future since it significantly eases build and installation
|
||||
considerations. "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2"
|
||||
is equal to 0.16.52 and will stop working. The CI artifacts will be
|
||||
updated shortly.
|
||||
|
||||
For example, for CentOS 7.x:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-0.16.46-0.x86_64.rpm
|
||||
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-devel-0.16.46-0.x86_64.rpm
|
||||
sudo rpm -i libyang-0.16.46-0.x86_64.rpm libyang-devel-0.16.46-0.x86_64.rpm
|
||||
|
||||
or Ubuntu 18.04:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb
|
||||
wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb
|
||||
sudo apt install libpcre3-dev
|
||||
sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb
|
||||
``libyang`` version 0.16.74 or newer is required to build FRR.
|
||||
|
||||
.. note::
|
||||
For Debian-based systems, the official libyang package requires recent
|
||||
versions of swig (3.0.12) and debhelper (11) which are only available in
|
||||
Debian buster (10). However, libyang packages built on Debian buster can
|
||||
be installed on both Debian jessie (8) and Debian stretch (9), as well as
|
||||
various Ubuntu systems. The python3-yang package will not work, but the
|
||||
other packages (libyang-dev is the one needed for FRR) will.
|
||||
|
||||
Alternatively, libyang can be built and installed manually by following
|
||||
the steps below:
|
||||
The ``libyang`` development packages need to be installed in addition to the
|
||||
libyang core package in order to build FRR successfully. Make sure to
|
||||
download and install those from the link above alongside the binary
|
||||
packages.
|
||||
|
||||
.. code-block:: shell
|
||||
Depending on your platform, you may also need to install the PCRE
|
||||
development package. Typically this is ``libpcre-dev`` or ``pcre-devel``.
|
||||
|
||||
git clone https://github.com/opensourcerouting/libyang
|
||||
.. note::
|
||||
|
||||
For Debian-based systems, the official ``libyang`` package requires recent
|
||||
versions of ``swig`` (3.0.12) and ``debhelper`` (11) which are only
|
||||
available in Debian buster (10). However, ``libyang`` packages built on
|
||||
Debian buster can be installed on both Debian jessie (8) and Debian stretch
|
||||
(9), as well as various Ubuntu systems. The ``python3-yang`` package will
|
||||
not work, but the other packages (``libyang-dev`` is the one needed for FRR)
|
||||
will.
|
||||
|
||||
**Option 2: Source Install**
|
||||
|
||||
.. note::
|
||||
|
||||
Ensure that the `libyang build requirements
|
||||
<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
|
||||
are met before continuing. Usually this entails installing ``cmake`` and
|
||||
``libpcre-dev`` or ``pcre-devel``.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
git clone https://github.com/CESNET/libyang.git
|
||||
cd libyang
|
||||
git checkout -b tmp origin/tmp
|
||||
mkdir build; cd build
|
||||
cmake -DENABLE_LYD_PRIV=ON ..
|
||||
cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
|
||||
make
|
||||
sudo make install
|
||||
|
||||
When building libyang on CentOS 6, it's also necessary to pass the
|
||||
``-DENABLE_CACHE=OFF`` parameter to cmake.
|
||||
|
||||
Note: please check the `libyang build requirements
|
||||
<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
|
||||
first.
|
||||
|
@ -12,7 +12,7 @@ Building FRR
|
||||
building-frr-for-centos7
|
||||
building-frr-for-debian8
|
||||
building-frr-for-debian9
|
||||
building-frr-for-fedora24
|
||||
building-frr-for-fedora
|
||||
building-frr-for-freebsd10
|
||||
building-frr-for-freebsd11
|
||||
building-frr-for-freebsd9
|
||||
|
@ -131,7 +131,7 @@ language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst']
|
||||
exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst', 'include-compile.rst']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
|
@ -6,7 +6,7 @@ Hooks
|
||||
Libfrr provides type-safe subscribable hook points where other pieces of
|
||||
code can add one or more callback functions. "type-safe" in this case
|
||||
applies to the function pointers used for subscriptions. The
|
||||
implementations checks (at compile-time) wheter a callback to be added has
|
||||
implementations checks (at compile-time) whether a callback to be added has
|
||||
the appropriate function signature (parameters) for the hook.
|
||||
|
||||
Example:
|
||||
|
37
doc/developer/include-compile.rst
Normal file
37
doc/developer/include-compile.rst
Normal 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
|
@ -18,7 +18,7 @@ maybe by a syslog collector from all routers.) Therefore, anything that
|
||||
needs to get the user in the loop—and only these things—are warnings or
|
||||
errors.
|
||||
|
||||
Note that this doesn't neccessarily mean the user needs to fix something in
|
||||
Note that this doesn't necessarily mean the user needs to fix something in
|
||||
the FRR instance. It also includes when we detect something else needs
|
||||
fixing, for example another router, the system we're running on, or the
|
||||
configuration. The common point is that the user should probably do
|
||||
|
@ -3,7 +3,7 @@
|
||||
Memtypes
|
||||
========
|
||||
|
||||
FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
|
||||
FRR includes wrappers around ``malloc()`` and ``free()`` that count the number
|
||||
of objects currently allocated, for each of a defined ``MTYPE``.
|
||||
|
||||
To this extent, there are *memory groups* and *memory types*. Each memory
|
||||
|
@ -284,7 +284,7 @@ Each message begins with the following header:
|
||||
The message type field can take one of the following values:
|
||||
|
||||
+-------------------------------+---------+
|
||||
| Messages to OSPF deamon | Value |
|
||||
| Messages to OSPF daemon | Value |
|
||||
+===============================+=========+
|
||||
| MSG\_REGISTER\_OPAQUETYPE | 1 |
|
||||
+-------------------------------+---------+
|
||||
@ -300,7 +300,7 @@ The message type field can take one of the following values:
|
||||
+-------------------------------+---------+
|
||||
|
||||
+-----------------------------+---------+
|
||||
| Messages from OSPF deamon | Value |
|
||||
| Messages from OSPF daemon | Value |
|
||||
+=============================+=========+
|
||||
| MSG\_REPLY | 10 |
|
||||
+-----------------------------+---------+
|
||||
|
@ -31,7 +31,7 @@ Implementation details
|
||||
Concepts
|
||||
^^^^^^^^
|
||||
|
||||
Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various
|
||||
Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various
|
||||
information:
|
||||
|
||||
* **Router Information:** flood the Segment Routing capabilities of the node.
|
||||
@ -40,7 +40,7 @@ information:
|
||||
* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
|
||||
* **Extended Prefix:** flood the Prefix Segment Identifier
|
||||
|
||||
The implementation follow previous TE and Router Information codes. It used the
|
||||
The implementation follows previous TE and Router Information codes. It used the
|
||||
OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This
|
||||
latter is mandatory for the implementation as it provides the Callback to
|
||||
Segment Routing functions (see below) when an Extended Link / Prefix or Router
|
||||
@ -71,7 +71,7 @@ The figure below shows the relation between the various files:
|
||||
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
|
||||
respectively ospf_ext.c.
|
||||
* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
|
||||
Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB
|
||||
Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB
|
||||
and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs.
|
||||
* ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque
|
||||
LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
|
||||
@ -129,8 +129,8 @@ Opaque LSA it is the `ospf_opaque_lsa_install_hook()`. For deletion, it is
|
||||
Note that incoming LSA which is already present in the LSDB will be inserted
|
||||
after the old instance of this LSA remove from the LSDB. Thus, after the first
|
||||
time, each incoming LSA will trigger a `delete` following by an `install`. This
|
||||
is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done
|
||||
by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage
|
||||
is not very helpful to handle real LSA deletion. In fact, LSA deletion is done
|
||||
by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage
|
||||
function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So,
|
||||
to handle LSA Flush, the best is to look to the LSA age to determine if it is
|
||||
an installation or a future deletion i.e. the flushed LSA is first store in the
|
||||
@ -144,7 +144,7 @@ introduced. When this command is activated, function
|
||||
`ospf_router_info_update_sr()` is called to indicate to Router Information
|
||||
process that Segment Routing TLVs must be flood. Same function is called to
|
||||
modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD)
|
||||
TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity
|
||||
TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility
|
||||
to modify this TLV is offer by the code.
|
||||
|
||||
When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
|
||||
@ -159,8 +159,8 @@ Extended Link Prefix LSAs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Like for Router Information, Segment Routing is activate at the Extended
|
||||
Link/Prefix level with new `segment-routing on` command. This trigger
|
||||
automtically the flooding of Extended Link LSA for all ospf interface where
|
||||
Link/Prefix level with new `segment-routing on` command. This triggers
|
||||
automatically the flooding of Extended Link LSA for all ospf interfaces where
|
||||
adjacency is full. For Extended Prefix LSA, the new CLI command
|
||||
`segment-routing prefix ...` will trigger the flooding of Prefix SID
|
||||
TLV/SubTLVs.
|
||||
@ -255,7 +255,7 @@ The first segment-routing statement enable it. The Second one set the SRGB,
|
||||
third line the MSD and finally, set the Prefix SID index for a given prefix.
|
||||
Note that only prefix of Loopback interface could be configured with a Prefix
|
||||
SID. It is possible to add `no-php-flag` at the end of the prefix command to
|
||||
disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop
|
||||
disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
|
||||
the MPLS label prior to sending the packet.
|
||||
|
||||
Known limitations
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _packaging-debian:
|
||||
|
||||
Packaging Debian
|
||||
================
|
||||
|
||||
|
85
doc/developer/packaging-redhat.rst
Normal file
85
doc/developer/packaging-redhat.rst
Normal 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`.
|
@ -7,3 +7,4 @@ Packaging
|
||||
|
||||
maintainer-release-build
|
||||
packaging-debian
|
||||
packaging-redhat
|
||||
|
@ -5,13 +5,12 @@
|
||||
dev_RSTFILES = \
|
||||
doc/developer/bgp-typecodes.rst \
|
||||
doc/developer/bgpd.rst \
|
||||
doc/developer/building-frr-for-openwrt.rst \
|
||||
doc/developer/building-frr-for-alpine.rst \
|
||||
doc/developer/building-frr-for-centos6.rst \
|
||||
doc/developer/building-frr-for-centos7.rst \
|
||||
doc/developer/building-frr-for-debian8.rst \
|
||||
doc/developer/building-frr-for-debian9.rst \
|
||||
doc/developer/building-frr-for-fedora24.rst \
|
||||
doc/developer/building-frr-for-fedora.rst \
|
||||
doc/developer/building-frr-for-freebsd10.rst \
|
||||
doc/developer/building-frr-for-freebsd11.rst \
|
||||
doc/developer/building-frr-for-freebsd9.rst \
|
||||
@ -19,6 +18,7 @@ dev_RSTFILES = \
|
||||
doc/developer/building-frr-for-netbsd7.rst \
|
||||
doc/developer/building-frr-for-omnios.rst \
|
||||
doc/developer/building-frr-for-openbsd6.rst \
|
||||
doc/developer/building-frr-for-openwrt.rst \
|
||||
doc/developer/building-frr-for-ubuntu1404.rst \
|
||||
doc/developer/building-frr-for-ubuntu1604.rst \
|
||||
doc/developer/building-frr-for-ubuntu1804.rst \
|
||||
@ -27,6 +27,7 @@ dev_RSTFILES = \
|
||||
doc/developer/cli.rst \
|
||||
doc/developer/conf.py \
|
||||
doc/developer/hooks.rst \
|
||||
doc/developer/include-compile.rst \
|
||||
doc/developer/index.rst \
|
||||
doc/developer/library.rst \
|
||||
doc/developer/logging.rst \
|
||||
@ -37,8 +38,9 @@ dev_RSTFILES = \
|
||||
doc/developer/ospf-api.rst \
|
||||
doc/developer/ospf-sr.rst \
|
||||
doc/developer/ospf.rst \
|
||||
doc/developer/packaging.rst \
|
||||
doc/developer/packaging-debian.rst \
|
||||
doc/developer/packaging-redhat.rst
|
||||
doc/developer/packaging.rst \
|
||||
doc/developer/testing.rst \
|
||||
doc/developer/topotests-snippets.rst \
|
||||
doc/developer/topotests.rst \
|
||||
|
@ -48,17 +48,17 @@ A sample of this snippet in a test can be found `here
|
||||
Interacting with equipment
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You might want to interact with the topology equipments during the tests and
|
||||
You might want to interact with the topology equipment during the tests and
|
||||
there are different ways to do so.
|
||||
|
||||
Notes:
|
||||
|
||||
1. When using the Topogen API, all the equipments code derive from ``Topogear``
|
||||
1. When using the Topogen API, all the equipment code derives from ``Topogear``
|
||||
(`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by
|
||||
yourself how the abstractions that will be mentioned here works.
|
||||
yourself how the abstractions that will be mentioned here work.
|
||||
|
||||
2. When not using the ``Topogen`` API there is only one way to interact with
|
||||
the equipments, which is by calling the ``mininet`` API functions directly
|
||||
the equipment, which is by calling the ``mininet`` API functions directly
|
||||
to spawn commands.
|
||||
|
||||
Interacting with the Linux sandbox
|
||||
@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures:
|
||||
|
||||
.. note::
|
||||
|
||||
``vtysh_(multi)cmd`` is only available for router type of equipments.
|
||||
``vtysh_(multi)cmd`` is only available for router types of equipment.
|
||||
|
||||
Invoking mininet CLI
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
@ -195,7 +195,7 @@ Loading JSON from a file:
|
||||
Comparing JSON output
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After obtaining JSON output formated with Python data structures, you may use
|
||||
After obtaining JSON output formatted with Python data structures, you may use
|
||||
it to assert a minimalist schema:
|
||||
|
||||
.. code:: py
|
||||
|
@ -151,7 +151,7 @@ Collect Memory Leak Information
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
FRR processes have the capabilities to report remaining memory allocations upon
|
||||
exit. To enable the reporting of the memory, define an enviroment variable
|
||||
exit. To enable the reporting of the memory, define an environment variable
|
||||
``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
|
||||
|
||||
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
|
||||
@ -410,7 +410,7 @@ Defining the Topology
|
||||
The first step to write a new test is to define the topology. This step can be
|
||||
done in many ways, but the recommended is to use Graphviz to generate a drawing
|
||||
of the topology. It allows us to see the topology graphically and to see the
|
||||
names of equipments, links and addresses.
|
||||
names of equipment, links and addresses.
|
||||
|
||||
Here is an example of Graphviz dot file that generates the template topology
|
||||
:file:`tests/topotests/example-test/test_template.dot` (the inlined code might
|
||||
|
@ -43,7 +43,7 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`.
|
||||
Command Extraction
|
||||
------------------
|
||||
|
||||
When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR
|
||||
When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR
|
||||
codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
|
||||
them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
|
||||
contains the name of the command plus ``_vtysh``, as well as a flag that
|
||||
@ -167,7 +167,7 @@ Protocol
|
||||
VTYSH communicates with FRR daemons by way of domain socket. Each daemon
|
||||
creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The
|
||||
protocol is very simple. In the VTYSH to daemon direction, messages are simply
|
||||
NULL-terminated strings, whose content are CLI commands. Here is a typical
|
||||
NUL-terminated strings, whose content are CLI commands. Here is a typical
|
||||
message from VTYSH to a daemon:
|
||||
|
||||
::
|
||||
@ -178,7 +178,7 @@ message from VTYSH to a daemon:
|
||||
00000010: 6c0a 00 l..
|
||||
|
||||
|
||||
The response format has some more data in it. First is a NULL-terminated string
|
||||
The response format has some more data in it. First is a NUL-terminated string
|
||||
containing the plaintext response, which is just the output of the command that
|
||||
was sent in the request. This is displayed to the user. The plaintext response
|
||||
is followed by 3 null marker bytes, followed by a 1-byte status code that
|
||||
|
@ -99,9 +99,14 @@ Bugfix releases are made as needed at 1 month intervals until the next
|
||||
``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
|
||||
bugfix releases may occur sooner.
|
||||
|
||||
Bugfixes are applied to the two most recent releases. Security fixes are
|
||||
backported to all releases less than or equal to at least one year old. Security
|
||||
fixes may also be backported to older releases depending on severity.
|
||||
Bugfixes are applied to the two most recent releases. However, backporting of bug
|
||||
fixes to older than the two most recent releases will not be prevented, if acked
|
||||
under the classical development workflow applying for a pull request.
|
||||
|
||||
Security fixes are backported to all releases less than or equal to at least one
|
||||
year old. Security fixes may also be backported to older releases depending on
|
||||
severity.
|
||||
|
||||
|
||||
Long term support branches ( LTS )
|
||||
-----------------------------------------
|
||||
@ -128,7 +133,7 @@ branch is required. The work can be shared by multiple people. In all cases, the
|
||||
must be at least one person that is in charge of the maintenance branch. The person
|
||||
on people responsible for a maintenance branch must be a FRR maintainer. Note that
|
||||
they may choose to abandon support for the maintenance branch at any time. If
|
||||
noone takes over the responsibility of the LTS branch, then the support will be
|
||||
no one takes over the responsibility of the LTS branch, then the support will be
|
||||
discontinued.
|
||||
|
||||
The LTS branch duties are the following ones:
|
||||
@ -371,7 +376,7 @@ system in which submissions from an individual representing one company should
|
||||
be merged by someone unaffiliated with that company.
|
||||
|
||||
Guidelines for code review
|
||||
""""""""""""""""""""""""""
|
||||
--------------------------
|
||||
|
||||
- As a rule of thumb, the depth of the review should be proportional to the
|
||||
scope and / or impact of the patch.
|
||||
|
@ -129,7 +129,7 @@ language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst']
|
||||
exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst', 'bfd-options.rst']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
|
@ -1,3 +1,3 @@
|
||||
.. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path]
|
||||
.. |synopsis-options-hv| replace:: [-h] [-v]
|
||||
.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8)
|
||||
.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), mtracebis(8)
|
||||
|
@ -390,7 +390,7 @@ Terminal Mode Commands
|
||||
.. index:: find COMMAND...
|
||||
.. clicmd:: find COMMAND...
|
||||
|
||||
This commmand performs a simple substring search across all defined commands
|
||||
This command performs a simple substring search across all defined commands
|
||||
in all modes. As an example, suppose you're in enable mode and can't
|
||||
remember where the command to turn OSPF segment routing on is:
|
||||
|
||||
|
@ -511,8 +511,8 @@ cause may lead to routing instability or oscillation across multiple speakers
|
||||
in iBGP topologies. This can occur with full-mesh iBGP, but is particularly
|
||||
problematic in non-full-mesh iBGP topologies that further reduce the routing
|
||||
information known to each speaker. This has primarily been documented with iBGP
|
||||
route-reflection topologies. However, any route-hiding technologies potentially
|
||||
could also exacerbate oscillation with MED.
|
||||
:ref:`route-reflection <bgp-route-reflector>` topologies. However, any
|
||||
route-hiding technologies potentially could also exacerbate oscillation with MED.
|
||||
|
||||
This second issue occurs where speakers each have only a subset of routes, and
|
||||
there are cycles in the preferences between different combinations of routes -
|
||||
@ -1145,7 +1145,7 @@ is 4 octet long. The following format is used to define the community value.
|
||||
``graceful-shutdown`` represents well-known communities value
|
||||
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
|
||||
the purpose Graceful BGP Session Shutdown to reduce the amount of
|
||||
lost traffic when taking BGP sessions down for maintainance. The use
|
||||
lost traffic when taking BGP sessions down for maintenance. The use
|
||||
of the community needs to be supported from your peers side to
|
||||
actually have any effect.
|
||||
|
||||
@ -1176,20 +1176,20 @@ is 4 octet long. The following format is used to define the community value.
|
||||
``llgr-stale``
|
||||
``llgr-stale`` represents well-known communities value ``LLGR_STALE``
|
||||
``0xFFFF0006`` ``65535:6``.
|
||||
Assigned and intented only for use with routers supporting the
|
||||
Assigned and intended only for use with routers supporting the
|
||||
Long-lived Graceful Restart Capability as described in
|
||||
[Draft-IETF-uttaro-idr-bgp-persistence]_.
|
||||
Routers recieving routes with this community may (depending on
|
||||
Routers receiving routes with this community may (depending on
|
||||
implementation) choose allow to reject or modify routes on the
|
||||
presence or absence of this community.
|
||||
|
||||
``no-llgr``
|
||||
``no-llgr`` represents well-known communities value ``NO_LLGR``
|
||||
``0xFFFF0007`` ``65535:7``.
|
||||
Assigned and intented only for use with routers supporting the
|
||||
Assigned and intended only for use with routers supporting the
|
||||
Long-lived Graceful Restart Capability as described in
|
||||
[Draft-IETF-uttaro-idr-bgp-persistence]_.
|
||||
Routers recieving routes with this community may (depending on
|
||||
Routers receiving routes with this community may (depending on
|
||||
implementation) choose allow to reject or modify routes on the
|
||||
presence or absence of this community.
|
||||
|
||||
@ -1251,7 +1251,7 @@ UPDATE messages.
|
||||
There are two types of community list:
|
||||
|
||||
standard
|
||||
This type accepts an explicit value for the atttribute.
|
||||
This type accepts an explicit value for the attribute.
|
||||
|
||||
expanded
|
||||
This type accepts a regular expression. Because the regex must be
|
||||
@ -2240,10 +2240,15 @@ Displaying Routes by AS Path
|
||||
Route Reflector
|
||||
===============
|
||||
|
||||
.. note:: This documentation is woefully incomplete.
|
||||
BGP routers connected inside the same AS through BGP belong to an internal
|
||||
BGP session, or IBGP. In order to prevent routing table loops, IBGP does not
|
||||
advertise IBGP-learned routes to other routers in the same session. As such,
|
||||
IBGP requires a full mesh of all peers. For large networks, this quickly becomes
|
||||
unscalable. Introducing route reflectors removes the need for the full-mesh.
|
||||
|
||||
.. index:: bgp cluster-id A.B.C.D
|
||||
.. clicmd:: bgp cluster-id A.B.C.D
|
||||
When route reflectors are configured, these will reflect the routes announced
|
||||
by the peers configured as clients. A route reflector client is configured
|
||||
with:
|
||||
|
||||
.. index:: neighbor PEER route-reflector-client
|
||||
.. clicmd:: neighbor PEER route-reflector-client
|
||||
@ -2251,6 +2256,13 @@ Route Reflector
|
||||
.. index:: no neighbor PEER route-reflector-client
|
||||
.. clicmd:: no neighbor PEER route-reflector-client
|
||||
|
||||
To avoid single points of failure, multiple route reflectors can be configured.
|
||||
|
||||
A cluster is a collection of route reflectors and their clients, and is used
|
||||
by route reflectors to avoid looping.
|
||||
|
||||
.. index:: bgp cluster-id A.B.C.D
|
||||
.. clicmd:: bgp cluster-id A.B.C.D
|
||||
|
||||
.. _routing-policy:
|
||||
|
||||
@ -2469,7 +2481,7 @@ certainly contains silly mistakes, if not serious flaws.
|
||||
route-map rm-no-export permit 20
|
||||
!
|
||||
route-map rm-blackhole permit 10
|
||||
description blackhole, up-pref and ensure it cant escape this AS
|
||||
description blackhole, up-pref and ensure it cannot escape this AS
|
||||
set ip next-hop 127.0.0.1
|
||||
set local-preference 10
|
||||
set community additive no-export
|
||||
|
@ -167,7 +167,7 @@ set. That VRF will then be selected. The below full configuration example
|
||||
depicts how Route Targets are configured and how VRFs and cross VRF
|
||||
configuration is done. Note that the VRF are mapped on Linux Network
|
||||
Namespaces. For data traffic to cross VRF boundaries, virtual ethernet
|
||||
interfaces are created with private IP adressing scheme.
|
||||
interfaces are created with private IP addressing scheme.
|
||||
|
||||
.. code-block:: frr
|
||||
|
||||
@ -322,7 +322,7 @@ There are some other known issues:
|
||||
- The validation procedure depicted in :rfc:`5575` is not available.
|
||||
|
||||
This validation procedure has not been implemented, as this feature was not
|
||||
used in the existing setups you shared wih us.
|
||||
used in the existing setups you shared with us.
|
||||
|
||||
- The filtering action shaper value, if positive, is not used to apply shaping.
|
||||
|
||||
|
@ -272,10 +272,11 @@ options from the list below.
|
||||
.. option:: --enable-multipath=X
|
||||
|
||||
Compile FRR with up to X way ECMP supported. This number can be from 0-999.
|
||||
For backwards compatability with older configure options when setting X = 0,
|
||||
For backwards compatibility with older configure options when setting X = 0,
|
||||
we will build FRR with 64 way ECMP. This is needed because there are
|
||||
hardcoded arrays that FRR builds towards, so we need to know how big to
|
||||
make these arrays at build time.
|
||||
make these arrays at build time. Additionally if this parameter is
|
||||
not passed in FRR will default to 16 ECMP.
|
||||
|
||||
.. option:: --enable-shell-access
|
||||
|
||||
|
@ -218,7 +218,7 @@ To start OSPF process you have to specify the OSPF router.
|
||||
SPF-triggering event occurs within the hold-time of the previous SPF
|
||||
calculation.
|
||||
|
||||
This command supercedes the *timers spf* command in previous FRR
|
||||
This command supersedes the *timers spf* command in previous FRR
|
||||
releases.
|
||||
|
||||
.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)
|
||||
|
@ -88,7 +88,7 @@ end destination.
|
||||
|
||||
When a incoming packet matches the destination prefix specified, take the
|
||||
packet and forward according to the nexthops specified. This command accepts
|
||||
both v4 and v6 prefixes. This command is used in conjuction of the
|
||||
both v4 and v6 prefixes. This command is used in conjunction of the
|
||||
:clicmd:`match src-ip PREFIX` command for matching.
|
||||
|
||||
.. clicmd:: set nexthop-group NAME
|
||||
|
@ -210,8 +210,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
|
||||
|
||||
Set the IGMP version used on this interface. The default value is 3.
|
||||
|
||||
.. index:: ip multicat boundary oil WORD
|
||||
.. clicmd:: ip multicat boundary oil WORD
|
||||
.. index:: ip multicast boundary oil WORD
|
||||
.. clicmd:: ip multicast boundary oil WORD
|
||||
|
||||
Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join
|
||||
or IGMP report is received on this interface and the Group is denied by the
|
||||
|
@ -29,7 +29,7 @@ documented elsewhere.
|
||||
Using SHARP
|
||||
===========
|
||||
|
||||
All sharp commands are under the enable node and preceeded by the ``sharp``
|
||||
All sharp commands are under the enable node and preceded by the ``sharp``
|
||||
keyword. At present, no sharp commands will be preserved in the config.
|
||||
|
||||
.. index:: sharp install
|
||||
|
@ -380,7 +380,7 @@ At startup, FRR detects the presence of that file. It detects that the file
|
||||
statistics information matches the same file statistics information as
|
||||
`/proc/self/ns/net` ( through stat() function). As statistics information
|
||||
matches, then `vrf0` stands for the new default namespace name.
|
||||
Consequently, the VRF naming `Default` will be overriden by the new discovered
|
||||
Consequently, the VRF naming `Default` will be overridden by the new discovered
|
||||
namespace name `vrf0`.
|
||||
|
||||
For those who don't use VRF backend with *Linux network namespace*, it is
|
||||
@ -422,7 +422,7 @@ in routing entry, and can be configured like a route:
|
||||
.. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
|
||||
.. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
|
||||
|
||||
NETWORK ans MASK stand for the IP prefix entry to be added as static
|
||||
NETWORK and MASK stand for the IP prefix entry to be added as static
|
||||
route entry.
|
||||
GATEWAY is the gateway IP address to reach, in order to reach the prefix.
|
||||
INTERFACE is the interface behind which the prefix is located.
|
||||
|
@ -1,35 +1,58 @@
|
||||
FROM alpine:3.7 as source-builder
|
||||
ARG commit
|
||||
RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \
|
||||
binutils binutils-libs bison bsd-compat-headers build-base \
|
||||
c-ares c-ares-dev ca-certificates cryptsetup-libs curl \
|
||||
device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \
|
||||
git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \
|
||||
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \
|
||||
libgomp libisoburn libisofs libltdl libressl libssh2 \
|
||||
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \
|
||||
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \
|
||||
patch pax-utils pcre perl pkgconf python2 python2-dev readline \
|
||||
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \
|
||||
groff gzip bc py-sphinx
|
||||
ADD . /src
|
||||
RUN (cd /src && \
|
||||
./bootstrap.sh && \
|
||||
./configure \
|
||||
# This stage builds a dist tarball from the source
|
||||
FROM alpine:edge as source-builder
|
||||
|
||||
RUN mkdir -p /src/alpine
|
||||
COPY alpine/APKBUILD.in /src/alpine
|
||||
RUN source /src/alpine/APKBUILD.in \
|
||||
&& echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
|
||||
&& apk add \
|
||||
--no-cache \
|
||||
--update-cache \
|
||||
$makedepends \
|
||||
gzip
|
||||
|
||||
COPY . /src
|
||||
ARG PKGVER
|
||||
RUN cd /src \
|
||||
&& ./bootstrap.sh \
|
||||
&& ./configure \
|
||||
--enable-numeric-version \
|
||||
--with-pkg-extra-version=_git$commit && \
|
||||
make dist)
|
||||
FROM alpine:3.7 as alpine-builder
|
||||
RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk
|
||||
ADD docker/alpine/alpine-build.sh /usr/bin/
|
||||
ADD docker/alpine/builder /etc/sudoers.d
|
||||
COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/
|
||||
--with-pkg-extra-version="_git$PKGVER" \
|
||||
&& make dist
|
||||
|
||||
# This stage builds an apk from the dist tarball
|
||||
FROM alpine:edge as alpine-builder
|
||||
# Don't use nocache here so that abuild can use the cache
|
||||
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
|
||||
&& apk add \
|
||||
--update-cache \
|
||||
abuild \
|
||||
alpine-conf \
|
||||
alpine-sdk \
|
||||
&& setup-apkcache /var/cache/apk \
|
||||
&& mkdir -p /pkgs/apk \
|
||||
&& echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/
|
||||
RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
|
||||
USER builder
|
||||
RUN /usr/bin/alpine-build.sh
|
||||
FROM alpine:3.7
|
||||
RUN cd /dist \
|
||||
&& abuild-keygen -a -n \
|
||||
&& abuild checksum \
|
||||
&& abuild -r -P /pkgs/apk
|
||||
|
||||
# This stage installs frr from the apk
|
||||
FROM alpine:edge
|
||||
RUN mkdir -p /pkgs/apk
|
||||
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
|
||||
RUN apk add --no-cache tini
|
||||
RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk
|
||||
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
|
||||
&& apk add \
|
||||
--no-cache \
|
||||
--update-cache \
|
||||
tini \
|
||||
&& apk add \
|
||||
--no-cache \
|
||||
--allow-untrusted /pkgs/apk/*/*.apk \
|
||||
&& rm -rf /pkgs
|
||||
COPY docker/alpine/docker-start /usr/lib/frr/docker-start
|
||||
ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
|
||||
|
@ -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
|
@ -1,17 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -v
|
||||
set -x
|
||||
|
||||
##
|
||||
# commit must be converted to decimal
|
||||
# Package version needs to be decimal
|
||||
##
|
||||
c=`git rev-parse --short=10 HEAD`
|
||||
commit=`printf '%u\n' 0x$c`
|
||||
docker build -f docker/alpine/Dockerfile \
|
||||
--build-arg commit=$commit -t frr:alpine-$c .
|
||||
id=`docker create frr:alpine-$c`
|
||||
docker cp ${id}:/pkgs/ docker
|
||||
docker rm $id
|
||||
docker rmi frr:alpine-$c
|
||||
GITREV="$(git rev-parse --short=10 HEAD)"
|
||||
PKGVER="$(printf '%u\n' 0x$GITREV)"
|
||||
|
||||
docker build \
|
||||
--pull \
|
||||
--file=docker/alpine/Dockerfile \
|
||||
--build-arg="PKGVER=$PKGVER" \
|
||||
--tag="frr:alpine-builder-$GITREV" \
|
||||
--target=alpine-builder \
|
||||
.
|
||||
|
||||
CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")"
|
||||
docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine
|
||||
docker rm "${CONTAINER_ID}"
|
||||
|
||||
docker build \
|
||||
--file=docker/alpine/Dockerfile \
|
||||
--build-arg="PKGVER=$PKGVER" \
|
||||
--tag="frr:alpine-$GITREV" \
|
||||
.
|
||||
|
||||
docker rmi "frr:alpine-builder-$GITREV"
|
||||
|
@ -1 +0,0 @@
|
||||
builder ALL=(ALL) NOPASSWD:ALL
|
@ -6,5 +6,7 @@ set -e
|
||||
# For volume mounts...
|
||||
##
|
||||
chown -R frr:frr /etc/frr
|
||||
/etc/init.d/frr start
|
||||
exec sleep 10000d
|
||||
/usr/lib/frr/frrinit.sh start
|
||||
|
||||
# Sleep forever
|
||||
exec tail -f /dev/null
|
@ -314,7 +314,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
||||
if (prefix->rij->count)
|
||||
return EIGRP_FSM_KEEP_STATE;
|
||||
|
||||
zlog_info("All reply received\n");
|
||||
zlog_info("All reply received");
|
||||
if (head->reported_distance < prefix->fdistance) {
|
||||
return EIGRP_FSM_EVENT_LR_FCS;
|
||||
}
|
||||
@ -344,7 +344,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
||||
} else if (prefix->rij->count) {
|
||||
return EIGRP_FSM_KEEP_STATE;
|
||||
} else {
|
||||
zlog_info("All reply received\n");
|
||||
zlog_info("All reply received");
|
||||
return EIGRP_FSM_EVENT_LR;
|
||||
}
|
||||
} else if (msg->packet_type == EIGRP_OPC_UPDATE
|
||||
@ -366,7 +366,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
||||
if (prefix->rij->count) {
|
||||
return EIGRP_FSM_KEEP_STATE;
|
||||
} else {
|
||||
zlog_info("All reply received\n");
|
||||
zlog_info("All reply received");
|
||||
if (head->reported_distance
|
||||
< prefix->fdistance) {
|
||||
return EIGRP_FSM_EVENT_LR_FCS;
|
||||
@ -390,7 +390,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
||||
} else if (prefix->rij->count) {
|
||||
return EIGRP_FSM_KEEP_STATE;
|
||||
} else {
|
||||
zlog_info("All reply received\n");
|
||||
zlog_info("All reply received");
|
||||
return EIGRP_FSM_EVENT_LR;
|
||||
}
|
||||
} else if (msg->packet_type == EIGRP_OPC_UPDATE
|
||||
|
@ -131,7 +131,7 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
if (tw_adj) {
|
||||
if (tw_adj->state > ISIS_THREEWAY_DOWN) {
|
||||
if (isis->debugs & DEBUG_ADJ_PACKETS) {
|
||||
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n",
|
||||
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d",
|
||||
iih->circuit->area->area_tag,
|
||||
iih->circuit->interface->name,
|
||||
tw_adj->state);
|
||||
@ -144,7 +144,7 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
|| tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
|
||||
|
||||
if (isis->debugs & DEBUG_ADJ_PACKETS) {
|
||||
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n",
|
||||
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.",
|
||||
iih->circuit->area->area_tag,
|
||||
iih->circuit->interface->name);
|
||||
}
|
||||
@ -1523,7 +1523,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
|
||||
}
|
||||
|
||||
if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed)
|
||||
zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n");
|
||||
zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!");
|
||||
|
||||
retval = ISIS_OK;
|
||||
out:
|
||||
|
@ -362,6 +362,10 @@ static int isis_zebra_read(int command, struct zclient *zclient,
|
||||
if (zapi_route_decode(zclient->ibuf, &api) < 0)
|
||||
return -1;
|
||||
|
||||
if (api.prefix.family == AF_INET6
|
||||
&& IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Avoid advertising a false default reachability. (A default
|
||||
* route installed by IS-IS gets redistributed from zebra back
|
||||
|
6
lib/if.c
6
lib/if.c
@ -396,6 +396,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
|
||||
struct interface *ifp;
|
||||
|
||||
switch (vrf_get_backend()) {
|
||||
case VRF_BACKEND_UNKNOWN:
|
||||
case VRF_BACKEND_NETNS:
|
||||
ifp = if_lookup_by_name(name, vrf_id);
|
||||
if (ifp)
|
||||
@ -1279,6 +1280,11 @@ static int lib_interface_create(enum nb_event event,
|
||||
vrf->name);
|
||||
return NB_ERR_VALIDATION;
|
||||
}
|
||||
|
||||
/* if VRF is netns or not yet known - init for instance
|
||||
* then assumption is that passed config is exact
|
||||
* then the user intent was not to use an other iface
|
||||
*/
|
||||
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
|
||||
ifp = if_lookup_by_name_all_vrf(ifname);
|
||||
if (ifp && ifp->vrf_id != vrf->vrf_id) {
|
||||
|
10
lib/log.c
10
lib/log.c
@ -991,6 +991,7 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE),
|
||||
DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
|
||||
DESC_ENTRY(ZEBRA_HELLO),
|
||||
DESC_ENTRY(ZEBRA_CAPABILITIES),
|
||||
DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
|
||||
DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
|
||||
DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE),
|
||||
@ -1012,6 +1013,7 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_VRF_LABEL),
|
||||
DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
|
||||
DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
|
||||
DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER),
|
||||
DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
|
||||
DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
|
||||
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
|
||||
@ -1023,6 +1025,9 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
|
||||
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
|
||||
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
|
||||
DESC_ENTRY(ZEBRA_FEC_REGISTER),
|
||||
DESC_ENTRY(ZEBRA_FEC_UNREGISTER),
|
||||
DESC_ENTRY(ZEBRA_FEC_UPDATE),
|
||||
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
|
||||
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
|
||||
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
|
||||
@ -1057,6 +1062,11 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_IPSET_DESTROY),
|
||||
DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
|
||||
DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE),
|
||||
DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER),
|
||||
DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER),
|
||||
DESC_ENTRY(ZEBRA_IPTABLE_ADD),
|
||||
DESC_ENTRY(ZEBRA_IPTABLE_DELETE),
|
||||
DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER),
|
||||
DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
|
||||
};
|
||||
#undef DESC_ENTRY
|
||||
|
@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b)
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return 0;
|
||||
|
||||
if (a && !b)
|
||||
return -1;
|
||||
|
||||
if (!a && b)
|
||||
return 1;
|
||||
|
||||
return sockunion_cmp(a, b);
|
||||
}
|
||||
|
||||
static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sockunion_cmp(&nh1->addr, &nh2->addr);
|
||||
ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -209,6 +223,9 @@ static void nhgl_delete(struct nexthop_hold *nh)
|
||||
|
||||
XFREE(MTYPE_TMP, nh->nhvrf_name);
|
||||
|
||||
if (nh->addr)
|
||||
sockunion_free(nh->addr);
|
||||
|
||||
XFREE(MTYPE_TMP, nh);
|
||||
}
|
||||
|
||||
@ -292,8 +309,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
|
||||
nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
|
||||
if (intf)
|
||||
nh->intf = XSTRDUP(MTYPE_TMP, intf);
|
||||
|
||||
nh->addr = *addr;
|
||||
if (addr)
|
||||
nh->addr = sockunion_dup(addr);
|
||||
|
||||
listnode_add_sort(nhgc->nhg_list, nh);
|
||||
}
|
||||
@ -308,7 +325,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
|
||||
if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
|
||||
sockunion_cmp(addr, &nh->addr) == 0 &&
|
||||
nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
|
||||
nhgc_cmp_helper(intf, nh->intf) == 0)
|
||||
break;
|
||||
}
|
||||
@ -320,13 +337,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
|
||||
return;
|
||||
|
||||
list_delete_node(nhgc->nhg_list, node);
|
||||
|
||||
if (nh->nhvrf_name)
|
||||
XFREE(MTYPE_TMP, nh->nhvrf_name);
|
||||
if (nh->intf)
|
||||
XFREE(MTYPE_TMP, nh->intf);
|
||||
|
||||
XFREE(MTYPE_TMP, nh);
|
||||
nhgl_delete(nh);
|
||||
}
|
||||
|
||||
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
||||
@ -347,36 +358,45 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
||||
|
||||
nhop->vrf_id = vrf->vrf_id;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET) {
|
||||
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||
if (intf) {
|
||||
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||
if (nhop->ifindex == IFINDEX_INTERNAL)
|
||||
return false;
|
||||
} else
|
||||
nhop->type = NEXTHOP_TYPE_IPV4;
|
||||
} else {
|
||||
memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
|
||||
if (intf) {
|
||||
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||
if (nhop->ifindex == IFINDEX_INTERNAL)
|
||||
return false;
|
||||
} else
|
||||
nhop->type = NEXTHOP_TYPE_IPV6;
|
||||
if (intf) {
|
||||
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||
if (nhop->ifindex == IFINDEX_INTERNAL)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
if (addr->sa.sa_family == AF_INET) {
|
||||
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||
if (intf)
|
||||
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||
else
|
||||
nhop->type = NEXTHOP_TYPE_IPV4;
|
||||
} else {
|
||||
nhop->gate.ipv6 = addr->sin6.sin6_addr;
|
||||
if (intf)
|
||||
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
else
|
||||
nhop->type = NEXTHOP_TYPE_IPV6;
|
||||
}
|
||||
} else
|
||||
nhop->type = NEXTHOP_TYPE_IFINDEX;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
"[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
|
||||
"[no] nexthop\
|
||||
<\
|
||||
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|
||||
|INTERFACE$intf\
|
||||
>\
|
||||
[nexthop-vrf NAME$name]",
|
||||
NO_STR
|
||||
"Specify one of the nexthops in this ECMP group\n"
|
||||
"v4 Address\n"
|
||||
"v6 Address\n"
|
||||
"Interface to use\n"
|
||||
"Interface to use\n"
|
||||
"If the nexthop is in a different vrf tell us\n"
|
||||
"The nexthop-vrf Name\n")
|
||||
{
|
||||
@ -385,13 +405,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
struct nexthop *nh;
|
||||
bool legal;
|
||||
|
||||
/*
|
||||
* This is impossible to happen as that the cli parser refuses
|
||||
* to let you get here without an addr, but the SA system
|
||||
* does not understand this intricacy
|
||||
*/
|
||||
assert(addr);
|
||||
|
||||
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
|
||||
|
||||
if (nhop.type == NEXTHOP_TYPE_IPV6
|
||||
@ -480,9 +493,10 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
vty_out(vty, "nexthop ");
|
||||
vty_out(vty, "nexthop");
|
||||
|
||||
vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
|
||||
if (nh->addr)
|
||||
vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf)));
|
||||
|
||||
if (nh->intf)
|
||||
vty_out(vty, " %s", nh->intf);
|
||||
@ -504,7 +518,7 @@ static int nexthop_group_write(struct vty *vty)
|
||||
vty_out(vty, "nexthop-group %s\n", nhgc->name);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
|
||||
vty_out(vty, " ");
|
||||
vty_out(vty, " ");
|
||||
nexthop_group_write_nexthop_internal(vty, nh);
|
||||
}
|
||||
|
||||
@ -526,7 +540,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
|
||||
struct nexthop nhop;
|
||||
struct nexthop *nh;
|
||||
|
||||
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
|
||||
if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
|
||||
nhh->intf,
|
||||
nhh->nhvrf_name))
|
||||
continue;
|
||||
@ -562,7 +576,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
|
||||
struct nexthop nhop;
|
||||
struct nexthop *nh;
|
||||
|
||||
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
|
||||
if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
|
||||
nhh->intf,
|
||||
nhh->nhvrf_name))
|
||||
continue;
|
||||
@ -600,7 +614,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
|
||||
struct nexthop nhop;
|
||||
|
||||
if (!nexthop_group_parse_nexthop(
|
||||
&nhop, &nhh->addr, nhh->intf,
|
||||
&nhop, nhh->addr, nhh->intf,
|
||||
nhh->nhvrf_name))
|
||||
continue;
|
||||
|
||||
|
@ -68,7 +68,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
|
||||
|
||||
struct nexthop_hold {
|
||||
char *nhvrf_name;
|
||||
union sockunion addr;
|
||||
union sockunion *addr;
|
||||
char *intf;
|
||||
};
|
||||
|
||||
|
@ -348,39 +348,58 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
|
||||
* configurations. Given a new subtree, calculate all new YANG data nodes,
|
||||
* excluding default leafs and leaf-lists. This is a recursive function.
|
||||
*/
|
||||
static void nb_config_diff_new_subtree(const struct lyd_node *dnode,
|
||||
struct nb_config_cbs *changes)
|
||||
static void nb_config_diff_created(const struct lyd_node *dnode,
|
||||
struct nb_config_cbs *changes)
|
||||
{
|
||||
enum nb_operation operation;
|
||||
struct lyd_node *child;
|
||||
|
||||
LY_TREE_FOR (dnode->child, child) {
|
||||
enum nb_operation operation;
|
||||
|
||||
switch (child->schema->nodetype) {
|
||||
case LYS_LEAF:
|
||||
case LYS_LEAFLIST:
|
||||
if (lyd_wd_default((struct lyd_node_leaf_list *)child))
|
||||
break;
|
||||
|
||||
if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
|
||||
operation = NB_OP_CREATE;
|
||||
else if (nb_operation_is_valid(NB_OP_MODIFY,
|
||||
child->schema))
|
||||
operation = NB_OP_MODIFY;
|
||||
else
|
||||
continue;
|
||||
|
||||
nb_config_diff_add_change(changes, operation, child);
|
||||
break;
|
||||
case LYS_CONTAINER:
|
||||
case LYS_LIST:
|
||||
if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
|
||||
nb_config_diff_add_change(changes, NB_OP_CREATE,
|
||||
child);
|
||||
nb_config_diff_new_subtree(child, changes);
|
||||
break;
|
||||
default:
|
||||
switch (dnode->schema->nodetype) {
|
||||
case LYS_LEAF:
|
||||
case LYS_LEAFLIST:
|
||||
if (lyd_wd_default((struct lyd_node_leaf_list *)dnode))
|
||||
break;
|
||||
|
||||
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
|
||||
operation = NB_OP_CREATE;
|
||||
else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
|
||||
operation = NB_OP_MODIFY;
|
||||
else
|
||||
return;
|
||||
|
||||
nb_config_diff_add_change(changes, operation, dnode);
|
||||
break;
|
||||
case LYS_CONTAINER:
|
||||
case LYS_LIST:
|
||||
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
|
||||
nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
|
||||
|
||||
/* Process child nodes recursively. */
|
||||
LY_TREE_FOR (dnode->child, child) {
|
||||
nb_config_diff_created(child, changes);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void nb_config_diff_deleted(const struct lyd_node *dnode,
|
||||
struct nb_config_cbs *changes)
|
||||
{
|
||||
if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
|
||||
nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
|
||||
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
|
||||
struct lyd_node *child;
|
||||
|
||||
/*
|
||||
* Non-presence containers need special handling since they
|
||||
* don't have "destroy" callbacks. In this case, what we need to
|
||||
* do is to call the "destroy" callbacks of their child nodes
|
||||
* when applicable (i.e. optional nodes).
|
||||
*/
|
||||
LY_TREE_FOR (dnode->child, child) {
|
||||
nb_config_diff_deleted(child, changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,42 +418,27 @@ static void nb_config_diff(const struct nb_config *config1,
|
||||
for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
|
||||
LYD_DIFFTYPE type;
|
||||
struct lyd_node *dnode;
|
||||
enum nb_operation operation;
|
||||
|
||||
type = diff->type[i];
|
||||
|
||||
switch (type) {
|
||||
case LYD_DIFF_CREATED:
|
||||
dnode = diff->second[i];
|
||||
|
||||
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
|
||||
operation = NB_OP_CREATE;
|
||||
else if (nb_operation_is_valid(NB_OP_MODIFY,
|
||||
dnode->schema))
|
||||
operation = NB_OP_MODIFY;
|
||||
else
|
||||
continue;
|
||||
nb_config_diff_created(dnode, changes);
|
||||
break;
|
||||
case LYD_DIFF_DELETED:
|
||||
dnode = diff->first[i];
|
||||
operation = NB_OP_DESTROY;
|
||||
nb_config_diff_deleted(dnode, changes);
|
||||
break;
|
||||
case LYD_DIFF_CHANGED:
|
||||
dnode = diff->second[i];
|
||||
operation = NB_OP_MODIFY;
|
||||
nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
|
||||
break;
|
||||
case LYD_DIFF_MOVEDAFTER1:
|
||||
case LYD_DIFF_MOVEDAFTER2:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
nb_config_diff_add_change(changes, operation, dnode);
|
||||
|
||||
if (type == LYD_DIFF_CREATED
|
||||
&& CHECK_FLAG(dnode->schema->nodetype,
|
||||
LYS_CONTAINER | LYS_LIST))
|
||||
nb_config_diff_new_subtree(dnode, changes);
|
||||
}
|
||||
|
||||
lyd_free_diff(diff);
|
||||
|
41
lib/privs.c
41
lib/privs.c
@ -708,19 +708,19 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
|
||||
|
||||
/* If we're already elevated, just return */
|
||||
pthread_mutex_lock(&(privs->mutex));
|
||||
if (++privs->refcount > 1) {
|
||||
pthread_mutex_unlock(&(privs->mutex));
|
||||
return privs;
|
||||
{
|
||||
if (++(privs->refcount) == 1) {
|
||||
errno = 0;
|
||||
if (privs->change(ZPRIVS_RAISE)) {
|
||||
zlog_err("%s: Failed to raise privileges (%s)",
|
||||
funcname, safe_strerror(errno));
|
||||
}
|
||||
errno = save_errno;
|
||||
privs->raised_in_funcname = funcname;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&(privs->mutex));
|
||||
|
||||
errno = 0;
|
||||
if (privs->change(ZPRIVS_RAISE)) {
|
||||
zlog_err("%s: Failed to raise privileges (%s)",
|
||||
funcname, safe_strerror(errno));
|
||||
}
|
||||
errno = save_errno;
|
||||
privs->raised_in_funcname = funcname;
|
||||
return privs;
|
||||
}
|
||||
|
||||
@ -733,19 +733,20 @@ void _zprivs_lower(struct zebra_privs_t **privs)
|
||||
|
||||
/* Don't lower privs if there's another caller */
|
||||
pthread_mutex_lock(&(*privs)->mutex);
|
||||
if (--((*privs)->refcount) > 0) {
|
||||
pthread_mutex_unlock(&(*privs)->mutex);
|
||||
return;
|
||||
{
|
||||
if (--((*privs)->refcount) == 0) {
|
||||
errno = 0;
|
||||
if ((*privs)->change(ZPRIVS_LOWER)) {
|
||||
zlog_err("%s: Failed to lower privileges (%s)",
|
||||
(*privs)->raised_in_funcname,
|
||||
safe_strerror(errno));
|
||||
}
|
||||
errno = save_errno;
|
||||
(*privs)->raised_in_funcname = NULL;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&(*privs)->mutex);
|
||||
|
||||
errno = 0;
|
||||
if ((*privs)->change(ZPRIVS_LOWER)) {
|
||||
zlog_err("%s: Failed to lower privileges (%s)",
|
||||
(*privs)->raised_in_funcname, safe_strerror(errno));
|
||||
}
|
||||
errno = save_errno;
|
||||
(*privs)->raised_in_funcname = NULL;
|
||||
*privs = NULL;
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,7 @@ struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id);
|
||||
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
|
||||
|
||||
static int vrf_backend;
|
||||
static int vrf_backend_configured;
|
||||
static struct zebra_privs_t *vrf_daemon_privs;
|
||||
static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
|
||||
|
||||
@ -613,12 +614,15 @@ int vrf_is_backend_netns(void)
|
||||
|
||||
int vrf_get_backend(void)
|
||||
{
|
||||
if (!vrf_backend_configured)
|
||||
return VRF_BACKEND_UNKNOWN;
|
||||
return vrf_backend;
|
||||
}
|
||||
|
||||
void vrf_configure_backend(int vrf_backend_netns)
|
||||
{
|
||||
vrf_backend = vrf_backend_netns;
|
||||
vrf_backend_configured = 1;
|
||||
}
|
||||
|
||||
int vrf_handler_create(struct vty *vty, const char *vrfname,
|
||||
@ -662,7 +666,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
|
||||
"VRF %u is already configured with VRF %s\n",
|
||||
vrf->vrf_id, vrf->name);
|
||||
else
|
||||
zlog_info("VRF %u is already configured with VRF %s\n",
|
||||
zlog_info("VRF %u is already configured with VRF %s",
|
||||
vrf->vrf_id, vrf->name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
@ -101,8 +101,9 @@ RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
|
||||
DECLARE_QOBJ_TYPE(vrf)
|
||||
|
||||
/* Allow VRF with netns as backend */
|
||||
#define VRF_BACKEND_VRF_LITE 0
|
||||
#define VRF_BACKEND_NETNS 1
|
||||
#define VRF_BACKEND_VRF_LITE 0
|
||||
#define VRF_BACKEND_NETNS 1
|
||||
#define VRF_BACKEND_UNKNOWN 2
|
||||
|
||||
extern struct vrf_id_head vrfs_by_id;
|
||||
extern struct vrf_name_head vrfs_by_name;
|
||||
|
@ -629,7 +629,7 @@ void zclient_init(struct zclient *zclient, int redist_default,
|
||||
}
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("zclient_start is called");
|
||||
zlog_debug("scheduling zclient connection");
|
||||
|
||||
zclient_event(ZCLIENT_SCHEDULE, zclient);
|
||||
}
|
||||
@ -2504,8 +2504,9 @@ static int zclient_read(struct thread *thread)
|
||||
length -= ZEBRA_HEADER_SIZE;
|
||||
|
||||
if (zclient_debug)
|
||||
zlog_debug("zclient 0x%p command 0x%x VRF %u\n",
|
||||
(void *)zclient, command, vrf_id);
|
||||
zlog_debug("zclient 0x%p command %s VRF %u",
|
||||
(void *)zclient, zserv_command_string(command),
|
||||
vrf_id);
|
||||
|
||||
switch (command) {
|
||||
case ZEBRA_CAPABILITIES:
|
||||
@ -2574,14 +2575,14 @@ static int zclient_read(struct thread *thread)
|
||||
break;
|
||||
case ZEBRA_NEXTHOP_UPDATE:
|
||||
if (zclient_debug)
|
||||
zlog_debug("zclient rcvd nexthop update\n");
|
||||
zlog_debug("zclient rcvd nexthop update");
|
||||
if (zclient->nexthop_update)
|
||||
(*zclient->nexthop_update)(command, zclient, length,
|
||||
vrf_id);
|
||||
break;
|
||||
case ZEBRA_IMPORT_CHECK_UPDATE:
|
||||
if (zclient_debug)
|
||||
zlog_debug("zclient rcvd import check update\n");
|
||||
zlog_debug("zclient rcvd import check update");
|
||||
if (zclient->import_check_update)
|
||||
(*zclient->import_check_update)(command, zclient,
|
||||
length, vrf_id);
|
||||
@ -2608,7 +2609,7 @@ static int zclient_read(struct thread *thread)
|
||||
break;
|
||||
case ZEBRA_FEC_UPDATE:
|
||||
if (zclient_debug)
|
||||
zlog_debug("zclient rcvd fec update\n");
|
||||
zlog_debug("zclient rcvd fec update");
|
||||
if (zclient->fec_update)
|
||||
(*zclient->fec_update)(command, zclient, length);
|
||||
break;
|
||||
|
@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area)
|
||||
|
||||
if (IS_AREA_STUB(area)) {
|
||||
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
|
||||
zlog_debug("Stubbing out area for if %s\n", area->name);
|
||||
zlog_debug("Stubbing out area for if %s", area->name);
|
||||
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
|
||||
} else if (IS_AREA_ENABLED(area)) {
|
||||
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
|
||||
zlog_debug("Normal area for if %s\n", area->name);
|
||||
zlog_debug("Normal area for if %s", area->name);
|
||||
OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
|
||||
ospf6_asbr_send_externals_to_area(area);
|
||||
}
|
||||
@ -450,7 +450,7 @@ DEFUN (area_range,
|
||||
|
||||
range->path.u.cost_config = cost;
|
||||
|
||||
zlog_debug("%s: for prefix %s, flag = %x\n", __func__,
|
||||
zlog_debug("%s: for prefix %s, flag = %x", __func__,
|
||||
argv[idx_ipv6_prefixlen]->arg, range->flag);
|
||||
if (range->rnode == NULL) {
|
||||
ospf6_route_add(range, oa->range_table);
|
||||
|
@ -1006,7 +1006,7 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
|
||||
|
||||
for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
|
||||
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
|
||||
zlog_debug("%s: Flooding AS-External LSA %s\n",
|
||||
zlog_debug("%s: Flooding AS-External LSA %s",
|
||||
__func__, lsa->name);
|
||||
ospf6_flood_area(NULL, lsa, oa);
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ void ospf6_spf_calculation(uint32_t router_id,
|
||||
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
|
||||
if (lsa == NULL) {
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s: No router LSA for area %s\n", __func__,
|
||||
zlog_debug("%s: No router LSA for area %s", __func__,
|
||||
oa->name);
|
||||
return;
|
||||
}
|
||||
|
@ -226,6 +226,9 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient,
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
|
||||
return 0;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
|
||||
return 0;
|
||||
|
||||
ifindex = api.nexthops[0].ifindex;
|
||||
nexthop = &api.nexthops[0].gate.ipv6;
|
||||
|
||||
|
@ -74,12 +74,12 @@ void api_opaque_lsa_print(struct lsa_header *data)
|
||||
olsa = (struct opaque_lsa *)data;
|
||||
|
||||
opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE;
|
||||
zlog_debug("apiserver_lsa_print: opaquelen=%d\n", opaquelen);
|
||||
zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen);
|
||||
|
||||
for (i = 0; i < opaquelen; i++) {
|
||||
zlog_debug("0x%x ", olsa->mydata[i]);
|
||||
}
|
||||
zlog_debug("\n");
|
||||
zlog_debug(" ");
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
@ -242,7 +242,7 @@ const char *ospf_api_errname(int errcode)
|
||||
void msg_print(struct msg *msg)
|
||||
{
|
||||
if (!msg) {
|
||||
zlog_debug("msg_print msg=NULL!\n");
|
||||
zlog_debug("msg_print msg=NULL!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp)
|
||||
|
||||
/* zlog_warn for debugging */
|
||||
zlog_warn("ospf_apiserver_del_if");
|
||||
zlog_warn("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status,
|
||||
zlog_warn("ifp name=%s status=%d index=%d", ifp->name, ifp->status,
|
||||
ifp->ifindex);
|
||||
|
||||
oi = ospf_apiserver_if_lookup_by_ifp(ifp);
|
||||
@ -2110,7 +2110,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa)
|
||||
for (i = 0; i < opaquelen; i++) {
|
||||
zlog_debug("0x%x ", olsa->data[i]);
|
||||
}
|
||||
zlog_debug("\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length,
|
||||
|
||||
oi = nbr->oi;
|
||||
|
||||
/* LS Request packet overflows interface MTU. */
|
||||
/* LS Request packet overflows interface MTU
|
||||
* delta is just number of bytes required for 1 LS Req
|
||||
* ospf_packet_max will return the number of bytes can
|
||||
* be accomodated without ospf header. So length+delta
|
||||
* can be compared to ospf_packet_max
|
||||
* to check if it can fit another lsreq in the same packet.
|
||||
*/
|
||||
|
||||
if (*length + delta > ospf_packet_max(oi))
|
||||
return 0;
|
||||
|
||||
@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s)
|
||||
{
|
||||
struct ospf_lsa *lsa;
|
||||
uint16_t length = OSPF_LS_REQ_MIN_SIZE;
|
||||
unsigned long delta = stream_get_endp(s) + 12;
|
||||
unsigned long delta = 12;
|
||||
struct route_table *table;
|
||||
struct route_node *rn;
|
||||
int i;
|
||||
@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
|
||||
|
||||
assert(lsa->data);
|
||||
|
||||
/* Will it fit? */
|
||||
if (length + delta + ntohs(lsa->data->length) > size_noauth)
|
||||
/* Will it fit? Minimum it has to fit atleast one */
|
||||
if ((length + delta + ntohs(lsa->data->length) > size_noauth) &&
|
||||
(count > 0))
|
||||
break;
|
||||
|
||||
/* Keep pointer to LS age. */
|
||||
@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
uint16_t length = OSPF_LS_ACK_MIN_SIZE;
|
||||
unsigned long delta = stream_get_endp(s) + 24;
|
||||
unsigned long delta = OSPF_LSA_HEADER_SIZE;
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
|
||||
assert(lsa);
|
||||
|
||||
if (length + delta > ospf_packet_max(oi))
|
||||
/* LS Ack packet overflows interface MTU
|
||||
* delta is just number of bytes required for
|
||||
* 1 LS Ack(1 LS Hdr) ospf_packet_max will return
|
||||
* the number of bytes can be accomodated without
|
||||
* ospf header. So length+delta can be compared
|
||||
* against ospf_packet_max to check if it can fit
|
||||
* another ls header in the same packet.
|
||||
*/
|
||||
if ((length + delta) > ospf_packet_max(oi))
|
||||
break;
|
||||
|
||||
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
|
||||
|
@ -1372,14 +1372,14 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
|
||||
}
|
||||
|
||||
else {
|
||||
zlog_debug(" Segment Routing Algorithm TLV:\n");
|
||||
zlog_debug(" Segment Routing Algorithm TLV:");
|
||||
for (i = 0; i < ntohs(algo->header.length); i++)
|
||||
switch (algo->value[i]) {
|
||||
case 0:
|
||||
zlog_debug(" Algorithm %d: SPF\n", i);
|
||||
zlog_debug(" Algorithm %d: SPF", i);
|
||||
break;
|
||||
case 1:
|
||||
zlog_debug(" Algorithm %d: Strict SPF\n", i);
|
||||
zlog_debug(" Algorithm %d: Strict SPF", i);
|
||||
break;
|
||||
default:
|
||||
zlog_debug(
|
||||
|
@ -901,7 +901,7 @@ static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type,
|
||||
/* Sanity check, if LSA type unknwon
|
||||
merley skip any LSA */
|
||||
if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) {
|
||||
zlog_debug("Strange request with LSA type %d\n", i);
|
||||
zlog_debug("Strange request with LSA type %d", i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1140,13 +1140,13 @@ ospf_rtrs_print (struct route_table *rtrs)
|
||||
if (path->nexthop.s_addr == 0)
|
||||
{
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug (" directly attached to %s\r\n",
|
||||
zlog_debug (" directly attached to %s\r",
|
||||
ifindex2ifname (path->ifindex), VRF_DEFAULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug (" via %s, %s\r\n",
|
||||
zlog_debug (" via %s, %s\r",
|
||||
inet_ntoa (path->nexthop),
|
||||
ifindex2ifname (path->ifindex), VRF_DEFAULT);
|
||||
}
|
||||
|
@ -1600,7 +1600,7 @@ static int ospf_sr_update_schedule(struct thread *t)
|
||||
monotime(&stop_time);
|
||||
|
||||
if (IS_DEBUG_OSPF_SR)
|
||||
zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n",
|
||||
zlog_debug("SR (%s): SPF Processing Time(usecs): %lld",
|
||||
__func__,
|
||||
(stop_time.tv_sec - start_time.tv_sec) * 1000000LL
|
||||
+ (stop_time.tv_usec - start_time.tv_usec));
|
||||
|
@ -3029,13 +3029,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
|
||||
if (ospf->stub_router_startup_time
|
||||
!= OSPF_STUB_ROUTER_UNCONFIGURED)
|
||||
json_object_int_add(
|
||||
json_vrf, "postStartEnabledMsecs",
|
||||
ospf->stub_router_startup_time / 1000);
|
||||
json_vrf, "postStartEnabledSecs",
|
||||
ospf->stub_router_startup_time);
|
||||
if (ospf->stub_router_shutdown_time
|
||||
!= OSPF_STUB_ROUTER_UNCONFIGURED)
|
||||
json_object_int_add(
|
||||
json_vrf, "preShutdownEnabledMsecs",
|
||||
ospf->stub_router_shutdown_time / 1000);
|
||||
json_vrf, "preShutdownEnabledSecs",
|
||||
ospf->stub_router_shutdown_time);
|
||||
} else {
|
||||
vty_out(vty,
|
||||
" Stub router advertisement is configured\n");
|
||||
@ -3511,8 +3511,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
|
||||
json_object_int_add(json_interface_sub, "cost",
|
||||
oi->output_cost);
|
||||
json_object_int_add(
|
||||
json_interface_sub, "transmitDelayMsecs",
|
||||
1000 / OSPF_IF_PARAM(oi, transmit_delay));
|
||||
json_interface_sub, "transmitDelaySecs",
|
||||
OSPF_IF_PARAM(oi, transmit_delay));
|
||||
json_object_string_add(json_interface_sub, "state",
|
||||
lookup_msg(ospf_ism_state_msg,
|
||||
oi->state, NULL));
|
||||
@ -3616,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
|
||||
if (OSPF_IF_PARAM(oi, fast_hello) == 0)
|
||||
json_object_int_add(
|
||||
json_interface_sub, "timerMsecs",
|
||||
1000 / OSPF_IF_PARAM(oi, v_hello));
|
||||
OSPF_IF_PARAM(oi, v_hello) * 1000);
|
||||
else
|
||||
json_object_int_add(
|
||||
json_interface_sub, "timerMsecs",
|
||||
1000 / OSPF_IF_PARAM(oi, fast_hello));
|
||||
json_object_int_add(json_interface_sub,
|
||||
"timerDeadMsecs",
|
||||
1000 / OSPF_IF_PARAM(oi, v_wait));
|
||||
"timerDeadSecs",
|
||||
OSPF_IF_PARAM(oi, v_wait));
|
||||
json_object_int_add(json_interface_sub,
|
||||
"timerWaitMsecs",
|
||||
1000 / OSPF_IF_PARAM(oi, v_wait));
|
||||
"timerWaitSecs",
|
||||
OSPF_IF_PARAM(oi, v_wait));
|
||||
json_object_int_add(
|
||||
json_interface_sub, "timerRetransmit",
|
||||
1000 / OSPF_IF_PARAM(oi, retransmit_interval));
|
||||
json_interface_sub, "timerRetransmitSecs",
|
||||
OSPF_IF_PARAM(oi, retransmit_interval));
|
||||
} else {
|
||||
vty_out(vty, " Timer intervals configured,");
|
||||
vty_out(vty, " Hello ");
|
||||
|
137
pbrd/pbr_nht.c
137
pbrd/pbr_nht.c
@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
static void
|
||||
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
struct nexthop_group nhg,
|
||||
enum nexthop_types_t nh_afi);
|
||||
enum nexthop_types_t nh_type);
|
||||
|
||||
/*
|
||||
* Nexthop refcount.
|
||||
@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
|
||||
|
||||
switch (pbrnc1->nexthop->type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
return true;
|
||||
return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
return pbrnc1->nexthop->gate.ipv4.s_addr
|
||||
@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
||||
|
||||
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
||||
pbr_map_check_nh_group_change(nhgc->name);
|
||||
|
||||
if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
|
||||
if (ifp)
|
||||
pbr_nht_nexthop_interface_update(ifp);
|
||||
}
|
||||
}
|
||||
|
||||
void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
||||
@ -274,7 +282,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
struct pbr_nexthop_cache pnhc_find = {};
|
||||
struct pbr_nexthop_cache *pnhc;
|
||||
enum nexthop_types_t nh_afi = nhop->type;
|
||||
enum nexthop_types_t nh_type = nhop->type;
|
||||
|
||||
/* find pnhgc by name */
|
||||
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
|
||||
@ -296,7 +304,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
||||
if (pnhgc->nhh->count)
|
||||
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
||||
else
|
||||
pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi);
|
||||
pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
|
||||
|
||||
pbr_map_check_nh_group_change(nhgc->name);
|
||||
}
|
||||
@ -372,39 +380,53 @@ void pbr_nht_route_removed_for_table(uint32_t table_id)
|
||||
* - AFI_MAX on error
|
||||
*/
|
||||
static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
|
||||
enum nexthop_types_t nh_afi)
|
||||
enum nexthop_types_t nh_type)
|
||||
{
|
||||
struct nexthop *nexthop;
|
||||
afi_t install_afi = AFI_MAX;
|
||||
bool v6, v4, bh;
|
||||
|
||||
if (nh_type) {
|
||||
switch (nh_type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
return AFI_IP;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
return AFI_IP6;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
return AFI_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
v6 = v4 = bh = false;
|
||||
|
||||
if (!nh_afi) {
|
||||
for (ALL_NEXTHOPS(nhg, nexthop)) {
|
||||
nh_afi = nexthop->type;
|
||||
for (ALL_NEXTHOPS(nhg, nexthop)) {
|
||||
nh_type = nexthop->type;
|
||||
|
||||
switch (nh_type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
v6 = true;
|
||||
install_afi = AFI_IP;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
v4 = true;
|
||||
install_afi = AFI_IP6;
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
bh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nh_afi) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
v6 = true;
|
||||
install_afi = AFI_IP;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
v4 = true;
|
||||
install_afi = AFI_IP6;
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
bh = true;
|
||||
/* Interface and/or blackhole nexthops only. */
|
||||
if (!v4 && !v6)
|
||||
install_afi = AFI_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bh && v6 && v4)
|
||||
DEBUGD(&pbr_dbg_nht,
|
||||
@ -423,9 +445,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
struct nexthop_group nhg)
|
||||
{
|
||||
afi_t install_afi;
|
||||
enum nexthop_types_t nh_afi = 0;
|
||||
enum nexthop_types_t nh_type = 0;
|
||||
|
||||
install_afi = pbr_nht_which_afi(nhg, nh_afi);
|
||||
install_afi = pbr_nht_which_afi(nhg, nh_type);
|
||||
|
||||
route_add(pnhgc, nhg, install_afi);
|
||||
}
|
||||
@ -433,11 +455,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
static void
|
||||
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
struct nexthop_group nhg,
|
||||
enum nexthop_types_t nh_afi)
|
||||
enum nexthop_types_t nh_type)
|
||||
{
|
||||
afi_t install_afi;
|
||||
|
||||
install_afi = pbr_nht_which_afi(nhg, nh_afi);
|
||||
install_afi = pbr_nht_which_afi(nhg, nh_type);
|
||||
|
||||
pnhgc->installed = false;
|
||||
pnhgc->valid = false;
|
||||
@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
|
||||
struct listnode *node;
|
||||
struct pbr_map_interface *pmi;
|
||||
struct nexthop *nh;
|
||||
enum nexthop_types_t nh_afi = 0;
|
||||
enum nexthop_types_t nh_type = 0;
|
||||
|
||||
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
|
||||
@ -542,13 +564,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
|
||||
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||
|
||||
nh = pbrms->nhg->nexthop;
|
||||
nh_afi = nh->type;
|
||||
nh_type = nh->type;
|
||||
lup.nexthop = nh;
|
||||
pnhc = hash_lookup(pnhgc->nhh, &lup);
|
||||
pnhc->parent = NULL;
|
||||
hash_release(pnhgc->nhh, pnhc);
|
||||
pbr_nh_delete(&pnhc);
|
||||
pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi);
|
||||
pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
|
||||
|
||||
hash_release(pbr_nhg_hash, pnhgc);
|
||||
|
||||
@ -653,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
|
||||
|
||||
struct pbr_nht_individual {
|
||||
struct zapi_route *nhr;
|
||||
struct interface *ifp;
|
||||
|
||||
uint32_t valid;
|
||||
};
|
||||
@ -716,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr)
|
||||
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
|
||||
}
|
||||
|
||||
static void
|
||||
pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
|
||||
void *data)
|
||||
{
|
||||
struct pbr_nexthop_cache *pnhc = b->data;
|
||||
struct pbr_nht_individual *pnhi = data;
|
||||
bool old_valid;
|
||||
|
||||
old_valid = pnhc->valid;
|
||||
|
||||
if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||
&& pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
|
||||
pnhc->valid = !!if_is_up(pnhi->ifp);
|
||||
|
||||
DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
|
||||
old_valid, pnhc->valid);
|
||||
|
||||
if (pnhc->valid)
|
||||
pnhi->valid += 1;
|
||||
}
|
||||
|
||||
static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
|
||||
void *data)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc = b->data;
|
||||
struct pbr_nht_individual pnhi;
|
||||
bool old_valid;
|
||||
|
||||
old_valid = pnhgc->valid;
|
||||
|
||||
pnhi.ifp = data;
|
||||
pnhi.valid = 0;
|
||||
hash_iterate(pnhgc->nhh,
|
||||
pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
|
||||
|
||||
/*
|
||||
* If any of the specified nexthops are valid we are valid
|
||||
*/
|
||||
pnhgc->valid = !!pnhi.valid;
|
||||
|
||||
if (old_valid != pnhgc->valid)
|
||||
pbr_map_check_nh_group_change(pnhgc->name);
|
||||
}
|
||||
|
||||
void pbr_nht_nexthop_interface_update(struct interface *ifp)
|
||||
{
|
||||
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
|
||||
ifp);
|
||||
}
|
||||
|
||||
static uint32_t pbr_nhg_hash_key(void *arg)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *nhgc =
|
||||
|
@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name);
|
||||
*/
|
||||
extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
|
||||
|
||||
/*
|
||||
* When we get a callback from zebra about an interface status update.
|
||||
*/
|
||||
extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
|
||||
|
||||
extern void pbr_nht_init(void);
|
||||
#endif
|
||||
|
@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
|
||||
}
|
||||
|
||||
DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
||||
"[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
|
||||
"[no] set nexthop\
|
||||
<\
|
||||
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|
||||
|INTERFACE$intf\
|
||||
>\
|
||||
[nexthop-vrf NAME$name]",
|
||||
NO_STR
|
||||
"Set for the PBR-MAP\n"
|
||||
"Specify one of the nexthops in this map\n"
|
||||
"v4 Address\n"
|
||||
"v6 Address\n"
|
||||
"Interface to use\n"
|
||||
"Interface to use\n"
|
||||
"If the nexthop is in a different vrf tell us\n"
|
||||
"The nexthop-vrf Name\n")
|
||||
{
|
||||
@ -255,45 +261,39 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
||||
memset(&nhop, 0, sizeof(nhop));
|
||||
nhop.vrf_id = vrf->vrf_id;
|
||||
|
||||
/*
|
||||
* Make SA happy. CLIPPY is not going to give us a NULL
|
||||
* addr.
|
||||
*/
|
||||
assert(addr);
|
||||
if (addr->sa.sa_family == AF_INET) {
|
||||
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||
if (intf) {
|
||||
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
||||
vty_out(vty,
|
||||
"Specified Intf %s does not exist in vrf: %s\n",
|
||||
intf, vrf->name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
} else
|
||||
nhop.type = NEXTHOP_TYPE_IPV4;
|
||||
} else {
|
||||
memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
|
||||
if (intf) {
|
||||
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
||||
vty_out(vty,
|
||||
"Specified Intf %s does not exist in vrf: %s\n",
|
||||
intf, vrf->name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
} else {
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
||||
vty_out(vty,
|
||||
"Specified a v6 LL with no interface, rejecting\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
nhop.type = NEXTHOP_TYPE_IPV6;
|
||||
if (intf) {
|
||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
||||
vty_out(vty,
|
||||
"Specified Intf %s does not exist in vrf: %s\n",
|
||||
intf, vrf->name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
if (addr->sa.sa_family == AF_INET) {
|
||||
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||
if (intf)
|
||||
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||
else
|
||||
nhop.type = NEXTHOP_TYPE_IPV4;
|
||||
} else {
|
||||
nhop.gate.ipv6 = addr->sin6.sin6_addr;
|
||||
if (intf)
|
||||
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
else {
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
||||
vty_out(vty,
|
||||
"Specified a v6 LL with no interface, rejecting\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
nhop.type = NEXTHOP_TYPE_IPV6;
|
||||
}
|
||||
}
|
||||
} else
|
||||
nhop.type = NEXTHOP_TYPE_IFINDEX;
|
||||
|
||||
if (pbrms->nhg)
|
||||
nh = nexthop_exists(pbrms->nhg, &nhop);
|
||||
else {
|
||||
@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
||||
pbr_map_check(pbrms);
|
||||
}
|
||||
|
||||
if (nhop.type == NEXTHOP_TYPE_IFINDEX) {
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
|
||||
if (ifp)
|
||||
pbr_nht_nexthop_interface_update(ifp);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -616,18 +624,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
|
||||
vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
|
||||
|
||||
if (pbrms->src)
|
||||
vty_out(vty, " match src-ip %s\n",
|
||||
vty_out(vty, " match src-ip %s\n",
|
||||
prefix2str(pbrms->src, buff, sizeof(buff)));
|
||||
|
||||
if (pbrms->dst)
|
||||
vty_out(vty, " match dst-ip %s\n",
|
||||
vty_out(vty, " match dst-ip %s\n",
|
||||
prefix2str(pbrms->dst, buff, sizeof(buff)));
|
||||
|
||||
if (pbrms->nhgrp_name)
|
||||
vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
|
||||
vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
|
||||
|
||||
if (pbrms->nhg) {
|
||||
vty_out(vty, " set ");
|
||||
vty_out(vty, " set ");
|
||||
nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user