summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am26
-rw-r--r--babeld/.gitignore5
-rw-r--r--babeld/Makefile10
-rw-r--r--babeld/Makefile.am29
-rw-r--r--babeld/subdir.am47
-rw-r--r--bgpd/bgp_attr.c81
-rw-r--r--bgpd/bgp_attr_evpn.c2
-rw-r--r--bgpd/bgp_evpn.c90
-rw-r--r--bgpd/bgp_evpn.h2
-rw-r--r--bgpd/bgp_evpn_private.h7
-rw-r--r--bgpd/bgp_evpn_vty.c504
-rw-r--r--bgpd/bgp_route.c33
-rw-r--r--bgpd/bgp_routemap.c158
-rw-r--r--bgpd/bgp_vty.c2
-rw-r--r--bgpd/bgp_zebra.c36
-rw-r--r--bgpd/bgp_zebra.h3
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--bgpd/rfapi/.gitignore1
-rwxr-xr-xconfigure.ac132
-rw-r--r--debian/frr.logrotate22
-rw-r--r--doc/Building_FRR_on_CentOS6.md1
-rw-r--r--doc/Building_FRR_on_CentOS7.md1
-rw-r--r--doc/Building_FRR_on_Debian8.md1
-rw-r--r--doc/Building_FRR_on_Fedora24.md1
-rw-r--r--doc/Building_FRR_on_FreeBSD10.md1
-rw-r--r--doc/Building_FRR_on_FreeBSD11.md1
-rw-r--r--doc/Building_FRR_on_FreeBSD9.md1
-rw-r--r--doc/Building_FRR_on_NetBSD6.md1
-rw-r--r--doc/Building_FRR_on_NetBSD7.md1
-rw-r--r--doc/Building_FRR_on_OmniOS.md1
-rw-r--r--doc/Building_FRR_on_OpenBSD6.md1
-rw-r--r--doc/Building_FRR_on_Ubuntu1204.md1
-rw-r--r--doc/Building_FRR_on_Ubuntu1404.md1
-rw-r--r--doc/Building_FRR_on_Ubuntu1604.md1
-rw-r--r--doc/Makefile.am14
-rw-r--r--doc/basic.texi2
-rw-r--r--doc/bgpd.texi7
-rw-r--r--doc/defines.texi.in2
-rw-r--r--doc/frr.texi23
-rw-r--r--doc/overview.texi12
-rw-r--r--doc/pimd.8.in4
-rw-r--r--doc/watchfrr.8.in166
-rw-r--r--doc/zebra.8.in8
-rw-r--r--eigrpd/.gitignore2
-rw-r--r--eigrpd/Makefile10
-rw-r--r--eigrpd/Makefile.am46
-rw-r--r--eigrpd/eigrp_dump.c1
-rw-r--r--eigrpd/subdir.am59
-rw-r--r--fpm/subdir.am1
-rw-r--r--isisd/.gitignore2
-rw-r--r--isisd/Makefile10
-rw-r--r--isisd/Makefile.am39
-rw-r--r--isisd/subdir.am71
-rw-r--r--ldpd/.gitignore2
-rw-r--r--ldpd/Makefile10
-rw-r--r--ldpd/Makefile.am30
-rw-r--r--ldpd/lde.c5
-rw-r--r--ldpd/ldp_vty_cmds.c18
-rw-r--r--ldpd/ldpd.c2
-rw-r--r--ldpd/ldpe.c1
-rw-r--r--ldpd/subdir.am55
-rw-r--r--lib/command.c1
-rw-r--r--lib/command.h1
-rw-r--r--lib/filter.c212
-rw-r--r--lib/gitversion.pl2
-rw-r--r--lib/grammar_sandbox_main.c5
-rw-r--r--lib/hash.c5
-rw-r--r--lib/hash.h5
-rw-r--r--lib/libfrr.c413
-rw-r--r--lib/libfrr.h5
-rw-r--r--lib/log.c62
-rw-r--r--lib/log.h3
-rw-r--r--lib/prefix.c704
-rw-r--r--lib/prefix.h16
-rw-r--r--lib/privs.c17
-rw-r--r--lib/privs.h1
-rw-r--r--lib/subdir.am20
-rw-r--r--lib/vty.c140
-rw-r--r--lib/vty.h7
-rw-r--r--lib/zclient.c114
-rw-r--r--lib/zclient.h15
-rw-r--r--nhrpd/.gitignore1
-rw-r--r--nhrpd/Makefile10
-rw-r--r--nhrpd/Makefile.am47
-rw-r--r--nhrpd/subdir.am43
-rw-r--r--ospf6d/.gitignore2
-rw-r--r--ospf6d/Makefile10
-rw-r--r--ospf6d/Makefile.am43
-rw-r--r--ospf6d/subdir.am66
-rw-r--r--ospfclient/.gitignore2
-rw-r--r--ospfclient/Makefile10
-rw-r--r--ospfclient/Makefile.am28
-rw-r--r--ospfclient/ospfclient.c1
-rw-r--r--ospfclient/subdir.am30
-rw-r--r--ospfd/.gitignore2
-rw-r--r--ospfd/Makefile10
-rw-r--r--ospfd/Makefile.am49
-rw-r--r--ospfd/subdir.am93
-rw-r--r--qpb/subdir.am1
-rw-r--r--redhat/README.rpm_build.md1
-rw-r--r--redhat/daemons2
-rw-r--r--redhat/frr.logrotate8
-rw-r--r--redhat/frr.spec.in10
-rw-r--r--ripd/.gitignore2
-rw-r--r--ripd/Makefile10
-rw-r--r--ripd/Makefile.am39
-rw-r--r--ripd/subdir.am42
-rw-r--r--ripngd/.gitignore2
-rw-r--r--ripngd/Makefile10
-rw-r--r--ripngd/Makefile.am28
-rw-r--r--ripngd/subdir.am36
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/lib/cli/common_cli.c5
-rw-r--r--tests/lib/test_privs.c1
-rw-r--r--tests/test_lblmgr.c3
-rw-r--r--tools/etc/frr/daemons.conf2
-rw-r--r--tools/etc/frr/frr.conf5
-rw-r--r--tools/etc/rsyslog.d/45-frr.conf36
-rwxr-xr-xtools/frr-reload.py40
-rw-r--r--vtysh/vtysh.c8
-rw-r--r--vtysh/vtysh_config.c11
-rw-r--r--watchfrr/Makefile.am2
-rw-r--r--watchfrr/watchfrr.c330
-rw-r--r--zebra/client_main.c6
-rw-r--r--zebra/if_netlink.c13
-rw-r--r--zebra/interface.h14
-rw-r--r--zebra/label_manager.c4
-rw-r--r--zebra/main.c8
-rw-r--r--zebra/redistribute.c5
-rw-r--r--zebra/zebra_mpls.c8
-rw-r--r--zebra/zebra_vrf.h5
-rw-r--r--zebra/zebra_vty.c92
-rw-r--r--zebra/zebra_vxlan.c1561
-rw-r--r--zebra/zebra_vxlan.h34
-rw-r--r--zebra/zebra_vxlan_private.h34
-rw-r--r--zebra/zserv.c127
138 files changed, 4465 insertions, 2093 deletions
diff --git a/.gitignore b/.gitignore
index 3ad6b1de1c..7ed1255d9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,3 +76,4 @@ GPATH
*.la
*.lo
compile_commands.json
+.dirstamp
diff --git a/Makefile.am b/Makefile.am
index 7cfe4a97e3..494fcd4d56 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,7 @@ noinst_LIBRARIES =
lib_LTLIBRARIES =
module_LTLIBRARIES =
pkginclude_HEADERS =
+nodist_pkginclude_HEADERS =
dist_examples_DATA =
include lib/subdir.am
@@ -29,16 +30,27 @@ include zebra/subdir.am
include qpb/subdir.am
include fpm/subdir.am
+include ripd/subdir.am
+include ripngd/subdir.am
+include ospfd/subdir.am
+include ospf6d/subdir.am
+include ospfclient/subdir.am
+include isisd/subdir.am
+include nhrpd/subdir.am
+include ldpd/subdir.am
+include babeld/subdir.am
+include eigrpd/subdir.am
+
SUBDIRS = . @LIBRFP@ @RFPTEST@ \
- @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \
- @ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ @BABELD@ \
- @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ \
+ @BGPD@ \
+ @PIMD@ \
+ @WATCHFRR@ @VTYSH@ @DOC@ \
@SOLARIS@ tests tools
-DIST_SUBDIRS = . bgpd ripd ripngd ospfd ospf6d ldpd \
- isisd watchfrr vtysh ospfclient doc tests \
- solaris pimd nhrpd eigrpd bgpd/rfp-example/librfp \
- bgpd/rfp-example/rfptest tools babeld \
+DIST_SUBDIRS = . bgpd \
+ watchfrr vtysh doc tests \
+ solaris pimd bgpd/rfp-example/librfp \
+ bgpd/rfp-example/rfptest tools \
# end
if PKGSRC
diff --git a/babeld/.gitignore b/babeld/.gitignore
index 8384763a65..fbdb90f677 100644
--- a/babeld/.gitignore
+++ b/babeld/.gitignore
@@ -2,6 +2,7 @@
!*.c
!*.h
!LICENCE
-!Makefile.am
+!Makefile
+!subdir.am
!babeld.conf.sample
-!.gitignore \ No newline at end of file
+!.gitignore
diff --git a/babeld/Makefile b/babeld/Makefile
new file mode 100644
index 0000000000..ae125e6e4d
--- /dev/null
+++ b/babeld/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. babeld/babeld
+%: ALWAYS
+ @$(MAKE) -s -C .. babeld/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/babeld/Makefile.am b/babeld/Makefile.am
deleted file mode 100644
index 39f748e7fa..0000000000
--- a/babeld/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(PICFLAGS) $(WERROR)
-AM_LDFLAGS = $(PILDFLAGS)
-
-noinst_LIBRARIES = libbabel.a
-sbin_PROGRAMS = babeld
-
-libbabel_a_SOURCES = \
- babel_zebra.c net.c kernel.c util.c source.c neighbour.c \
- route.c xroute.c message.c resend.c babel_interface.c babeld.c \
- babel_filter.c babel_memory.c
-
-noinst_HEADERS = \
- babel_zebra.h net.h kernel.h util.h source.h neighbour.h \
- route.h xroute.h message.h resend.h babel_interface.h babeld.h \
- babel_filter.h babel_main.h babel_memory.h
-
-babeld_SOURCES = \
- babel_main.c $(libbabel_a_SOURCES)
-
-babeld_LDADD = ../lib/libfrr.la @LIBCAP@
-
-examplesdir = $(exampledir)
-dist_examples_DATA = babeld.conf.sample
diff --git a/babeld/subdir.am b/babeld/subdir.am
new file mode 100644
index 0000000000..c44cb275c2
--- /dev/null
+++ b/babeld/subdir.am
@@ -0,0 +1,47 @@
+#
+# babeld
+#
+
+if BABELD
+noinst_LIBRARIES += babeld/libbabel.a
+sbin_PROGRAMS += babeld/babeld
+dist_examples_DATA += babeld/babeld.conf.sample
+endif
+
+babeld_libbabel_a_SOURCES = \
+ babeld/babel_filter.c \
+ babeld/babel_interface.c \
+ babeld/babel_memory.c \
+ babeld/babel_zebra.c \
+ babeld/babeld.c \
+ babeld/kernel.c \
+ babeld/message.c \
+ babeld/neighbour.c \
+ babeld/net.c \
+ babeld/resend.c \
+ babeld/route.c \
+ babeld/source.c \
+ babeld/util.c \
+ babeld/xroute.c \
+ # end
+
+noinst_HEADERS += \
+ babeld/babel_filter.h \
+ babeld/babel_interface.h \
+ babeld/babel_main.h \
+ babeld/babel_memory.h \
+ babeld/babel_zebra.h \
+ babeld/babeld.h \
+ babeld/kernel.h \
+ babeld/message.h \
+ babeld/neighbour.h \
+ babeld/net.h \
+ babeld/resend.h \
+ babeld/route.h \
+ babeld/source.h \
+ babeld/util.h \
+ babeld/xroute.h \
+ # end
+
+babeld_babeld_SOURCES = babeld/babel_main.c
+babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la @LIBCAP@
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index dd18797637..b03b408f7d 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2606,10 +2606,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
stream_putc(s, pkt_safi); /* SAFI */
/* Nexthop AFI */
- if (afi == AFI_IP && safi == SAFI_UNICAST) {
+ if (afi == AFI_IP
+ && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
- } else if (safi == SAFI_LABELED_UNICAST)
- nh_afi = afi;
else
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
@@ -2800,9 +2799,8 @@ static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
if (attrlenfield > 0xff) {
/* 2-octet length field */
- stream_putc(s,
- BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, attrtype);
stream_putw(s, attrlenfield & 0xffff);
} else {
@@ -3040,15 +3038,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
if (attr->community->size * 4 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putw(s, attr->community->size * 4);
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putc(s, attr->community->size * 4);
}
@@ -3062,15 +3059,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
PEER_FLAG_SEND_LARGE_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
if (attr->lcommunity->size * 12 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putw(s, attr->lcommunity->size * 12);
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc(s, attr->lcommunity->size * 12);
}
@@ -3122,16 +3118,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
if (peer->sort == BGP_PEER_IBGP
|| peer->sort == BGP_PEER_CONFED) {
if (attr->ecommunity->size * 8 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
stream_putw(s, attr->ecommunity->size * 8);
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
stream_putc(s, attr->ecommunity->size * 8);
}
@@ -3197,9 +3191,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
label_index = attr->label_index;
if (label_index != BGP_INVALID_LABEL_INDEX) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID);
stream_putc(s, 10);
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
@@ -3227,9 +3220,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
*/
aspath = aspath_delete_confed_seq(aspath);
- stream_putc(s,
- BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_AS4_PATH);
aspath_sizep = stream_get_endp(s);
stream_putw(s, 0);
@@ -3414,15 +3406,14 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
if (attr->community->size * 4 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putw(s, attr->community->size * 4);
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putc(s, attr->community->size * 4);
}
@@ -3432,15 +3423,14 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Large Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
if (attr->lcommunity->size * 12 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putw(s, attr->lcommunity->size * 12);
} else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc(s, attr->lcommunity->size * 12);
}
@@ -3485,9 +3475,8 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Prefix SID */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID);
stream_putc(s, 10);
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
index 2f0b566ccf..6ead059261 100644
--- a/bgpd/bgp_attr_evpn.c
+++ b/bgpd/bgp_attr_evpn.c
@@ -169,7 +169,7 @@ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
prefix_copy(src, dst);
memset(dst, 0, sizeof(struct prefix));
p_evpn_p = &(dst->u.prefix_evpn);
- dst->family = AF_ETHERNET;
+ dst->family = AF_EVPN;
p_evpn_p->route_type = evpn_type;
if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
p_evpn_p->eth_tag = eth_tag;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index fe311832a2..0560dc46f9 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -347,9 +347,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
s = zclient->obuf;
stream_reset(s);
- zclient_create_header(
- s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL,
- bgp->vrf_id);
+ zclient_create_header(s, add ? ZEBRA_REMOTE_MACIP_ADD
+ : ZEBRA_REMOTE_MACIP_DEL,
+ bgp->vrf_id);
stream_putl(s, vpn->vni);
stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */
/* IP address length and IP address, if any. */
@@ -400,9 +400,9 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
s = zclient->obuf;
stream_reset(s);
- zclient_create_header(
- s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL,
- bgp->vrf_id);
+ zclient_create_header(s, add ? ZEBRA_REMOTE_VTEP_ADD
+ : ZEBRA_REMOTE_VTEP_DEL,
+ bgp->vrf_id);
stream_putl(s, vpn->vni);
if (IS_EVPN_PREFIX_IPADDR_V4(p))
stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4);
@@ -472,7 +472,7 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
{
struct ecommunity ecom_tmp;
struct ecommunity_val eval;
- struct ecommunity *ecom_mm;
+ u_int8_t *ecom_val_ptr;
int i;
u_int8_t *pnt;
int type = 0;
@@ -482,7 +482,7 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
encode_mac_mobility_extcomm(0, seq_num, &eval);
/* Find current MM ecommunity */
- ecom_mm = NULL;
+ ecom_val_ptr = NULL;
if (attr->ecommunity) {
for (i = 0; i < attr->ecommunity->size; i++) {
@@ -493,17 +493,17 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
if (type == ECOMMUNITY_ENCODE_EVPN
&& sub_type
== ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
- ecom_mm = (struct ecommunity *)
- attr->ecommunity->val
- + (i * 8);
+ ecom_val_ptr =
+ (u_int8_t *)(attr->ecommunity->val
+ + (i * 8));
break;
}
}
}
/* Update the existing MM ecommunity */
- if (ecom_mm) {
- memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE);
+ if (ecom_val_ptr) {
+ memcpy(ecom_val_ptr, eval.val, sizeof(char) * ECOMMUNITY_SIZE);
}
/* Add MM to existing */
else {
@@ -704,7 +704,7 @@ static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn)
static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
afi_t afi, safi_t safi, struct bgp_node *rn,
struct attr *attr, int add, int vni_table,
- struct bgp_info **ri)
+ struct bgp_info **ri, u_char flags)
{
struct bgp_info *tmp_ri;
struct bgp_info *local_ri, *remote_ri;
@@ -751,8 +751,11 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* remote, we have to initiate appropriate MAC mobility steps.
* This
* is applicable when updating the VNI routing table.
+ * We need to skip mobility steps for g/w macs (local mac on g/w
+ * SVI) advertised in EVPN.
+ * This will ensure that local routes are preferred for g/w macs
*/
- if (remote_ri) {
+ if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
u_int32_t cur_seqnum;
/* Add MM extended community to route. */
@@ -811,7 +814,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* and schedule for processing.
*/
static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_evpn *p, u_char sticky)
+ struct prefix_evpn *p, u_char flags)
{
struct bgp_node *rn;
struct attr attr;
@@ -828,7 +831,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
- attr.sticky = sticky;
+ attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
/* Set up RT and ENCAP extended community. */
build_evpn_route_extcomm(vpn, &attr);
@@ -839,7 +842,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
/* Create or update route entry. */
route_change = update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
- 1, 1, &ri);
+ 1, 1, &ri, flags);
assert(ri);
attr_new = ri->attr;
@@ -860,7 +863,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)p, &vpn->prd);
update_evpn_route_entry(bgp, vpn, afi, safi, rn, attr_new, 1, 0,
- &global_ri);
+ &global_ri, flags);
/* Schedule for processing and unlock node. */
bgp_process(bgp, rn, afi, safi);
@@ -998,10 +1001,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
if (evpn_route_is_sticky(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
- &attr_sticky, 0, 1, &ri);
+ &attr_sticky, 0, 1, &ri, 0);
else
update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
- 0, 1, &ri);
+ 0, 1, &ri, 0);
/* If a local route exists for this prefix, we need to update
* the global routing table too.
@@ -1022,7 +1025,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
(struct prefix *)evp, &vpn->prd);
assert(rd_rn);
update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0,
- 0, &global_ri);
+ 0, &global_ri, 0);
/* Schedule for processing and unlock node. */
bgp_process(bgp, rd_rn, afi, safi);
@@ -1190,6 +1193,12 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
{
struct prefix_evpn p;
+ /* If VNI is not live, we only need to update the originator ip */
+ if (!is_vni_live(vpn)) {
+ vpn->originator_ip = originator_ip;
+ return 0;
+ }
+
/* Need to withdraw type-3 route as the originator IP is part
* of the key.
*/
@@ -1631,8 +1640,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)&p, &vpn->prd);
- update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0,
- &ri);
+ update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, &ri,
+ 0);
/* Schedule for processing and unlock node. */
bgp_process(bgp, global_rn, afi, safi);
@@ -1665,7 +1674,7 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
(struct prefix *)evp, &vpn->prd);
assert(global_rn);
update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1,
- 0, &global_ri);
+ 0, &global_ri, 0);
/* Schedule for processing and unlock node. */
bgp_process(bgp, global_rn, afi, safi);
@@ -1798,7 +1807,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
/* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn));
- p.family = AF_ETHERNET;
+ p.family = AF_EVPN;
p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
@@ -1887,7 +1896,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
/* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn));
- p.family = AF_ETHERNET;
+ p.family = AF_EVPN;
p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_IMET_ROUTE;
@@ -1952,7 +1961,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
/* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn));
- p.family = AF_ETHERNET;
+ p.family = AF_EVPN;
p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
/* Additional information outside of prefix - ESI and GW IP */
@@ -2021,7 +2030,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
struct evpn_addr *p_evpn_p;
memset(&temp, 0, 16);
- if (p->family != AF_ETHERNET)
+ if (p->family != AF_EVPN)
return;
p_evpn_p = &(p->u.prefix_evpn);
@@ -2204,7 +2213,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
PREFIX2STR_BUFFER));
}
} else {
- /* Currently, this is to cater to other AF_ETHERNET code. */
+ /* For EVPN route types not supported yet. */
}
return (buf);
@@ -2586,7 +2595,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
* Handle add of a local MACIP.
*/
int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
- struct ipaddr *ip, u_char sticky)
+ struct ipaddr *ip, u_char flags)
{
struct bgpevpn *vpn;
struct prefix_evpn p;
@@ -2606,13 +2615,15 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
/* Create EVPN type-2 route and schedule for processing. */
build_evpn_type2_prefix(&p, mac, ip);
- if (update_evpn_route(bgp, vpn, &p, sticky)) {
+ if (update_evpn_route(bgp, vpn, &p, flags)) {
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
zlog_err(
- "%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s",
- bgp->vrf_id, vpn->vni, sticky ? "sticky" : "",
+ "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s",
+ bgp->vrf_id, vpn->vni,
+ CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway"
+ : "",
prefix_mac2str(mac, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)));
return -1;
@@ -2671,14 +2682,15 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
/* Lookup VNI. If present and no change, exit. */
vpn = bgp_evpn_lookup_vni(bgp, vni);
- if (vpn && is_vni_live(vpn)) {
- if (IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
+ if (vpn) {
+ if (is_vni_live(vpn)
+ && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
/* Probably some other param has changed that we don't
* care about. */
return 0;
/* Local tunnel endpoint IP address has changed */
- return handle_tunnel_ip_change(bgp, vpn, originator_ip);
+ handle_tunnel_ip_change(bgp, vpn, originator_ip);
}
/* Create or update as appropriate. */
@@ -2692,6 +2704,10 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
}
}
+ /* if the VNI is live already, there is nothibng more to do */
+ if (is_vni_live(vpn))
+ return 0;
+
/* Mark as "live" */
SET_FLAG(vpn->flags, VNI_FLAG_LIVE);
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index f4c7e68a5d..e9b7857212 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -42,7 +42,7 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip);
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
- u_char sticky);
+ u_char flags);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip);
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 095dfa1b15..9dc459cd4e 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -58,6 +58,9 @@ struct bgpevpn {
#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */
#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */
+ /* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
+ u_int8_t advertise_gw_macip;
+
/* Id for deriving the RD automatically for this VNI */
u_int16_t rd_id;
@@ -171,7 +174,7 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
struct ipaddr *ip)
{
memset(p, 0, sizeof(struct prefix_evpn));
- p->family = AF_ETHERNET;
+ p->family = AF_EVPN;
p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN);
@@ -184,7 +187,7 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
struct in_addr originator_ip)
{
memset(p, 0, sizeof(struct prefix_evpn));
- p->family = AF_ETHERNET;
+ p->family = AF_EVPN;
p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_IMET_ROUTE;
p->prefix.ip.ipa_type = IPADDR_V4;
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 1225354c0a..948c7f50f2 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -195,6 +195,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn)
vty_out(vty, " RD: %s\n",
prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
vty_out(vty, " Originator IP: %s\n", inet_ntoa(vpn->originator_ip));
+ vty_out(vty, " Advertise-gw-macip : %s\n",
+ vpn->advertise_gw_macip ? "Yes" : "No");
vty_out(vty, " Import Route Target:\n");
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
@@ -1642,6 +1644,51 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp)
}
/*
+ * evpn - enable advertisement of default g/w
+ */
+static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn)
+{
+ if (!vpn) {
+ if (bgp->advertise_gw_macip)
+ return;
+
+ bgp->advertise_gw_macip = 1;
+ bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
+ } else {
+ if (vpn->advertise_gw_macip)
+ return;
+
+ vpn->advertise_gw_macip = 1;
+ bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
+ vpn->vni);
+ }
+ return;
+}
+
+/*
+ * evpn - disable advertisement of default g/w
+ */
+static void evpn_unset_advertise_default_gw(struct bgp *bgp,
+ struct bgpevpn *vpn)
+{
+ if (!vpn) {
+ if (!bgp->advertise_gw_macip)
+ return;
+
+ bgp->advertise_gw_macip = 0;
+ bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
+ } else {
+ if (!vpn->advertise_gw_macip)
+ return;
+
+ vpn->advertise_gw_macip = 0;
+ bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
+ vpn->vni);
+ }
+ return;
+}
+
+/*
* EVPN (VNI advertisement) enabled. Register with zebra.
*/
static void evpn_set_advertise_all_vni(struct bgp *bgp)
@@ -1700,6 +1747,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write)
}
}
+ if (vpn->advertise_gw_macip)
+ vty_out(vty, " advertise-default-gw\n");
+
vty_out(vty, " exit-vni\n");
}
}
@@ -1712,6 +1762,77 @@ static void write_vni_config_for_entry(struct hash_backet *backet,
}
#if defined(HAVE_CUMULUS)
+DEFUN (bgp_evpn_advertise_default_gw_vni,
+ bgp_evpn_advertise_default_gw_vni_cmd,
+ "advertise-default-gw",
+ "Advertise defualt g/w mac-ip routes in EVPN for a VNI\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ if (!vpn)
+ return CMD_WARNING;
+
+ evpn_set_advertise_default_gw(bgp, vpn);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_default_vni_gw,
+ no_bgp_evpn_advertise_default_gw_vni_cmd,
+ "no advertise-default-gw",
+ NO_STR
+ "Withdraw default g/w mac-ip routes from EVPN for a VNI\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ if (!vpn)
+ return CMD_WARNING;
+
+ evpn_unset_advertise_default_gw(bgp, vpn);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (bgp_evpn_advertise_default_gw,
+ bgp_evpn_advertise_default_gw_cmd,
+ "advertise-default-gw",
+ "Advertise All defualt g/w mac-ip routes in EVPN\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ evpn_set_advertise_default_gw(bgp, NULL);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_default_gw,
+ no_bgp_evpn_advertise_default_gw_cmd,
+ "no advertise-default-gw",
+ NO_STR
+ "Withdraw All default g/w mac-ip routes from EVPN\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ evpn_unset_advertise_default_gw(bgp, NULL);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (bgp_evpn_advertise_all_vni,
bgp_evpn_advertise_all_vni_cmd,
"advertise-all-vni",
@@ -1739,86 +1860,95 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_vni,
- show_bgp_evpn_vni_cmd,
- "show bgp evpn vni",
+/*
+ * Display VNI information - for all or a specific VNI
+ */
+DEFUN (show_bgp_l2vpn_evpn_vni,
+ show_bgp_l2vpn_evpn_vni_cmd,
+ "show bgp l2vpn evpn vni [(1-16777215)]",
SHOW_STR
BGP_STR
+ L2VPN_HELP_STR
EVPN_HELP_STR
- "Show VNI\n")
-{
- struct bgp *bgp;
-
- bgp = bgp_get_default();
- if (!bgp)
- return CMD_WARNING;
-
- vty_out(vty, "Advertise All VNI flag: %s\n",
- bgp->advertise_all_vni ? "Enabled" : "Disabled");
-
- evpn_show_all_vnis(vty, bgp);
- return CMD_SUCCESS;
-}
-
-DEFUN (show_bgp_evpn_vni_num,
- show_bgp_evpn_vni_num_cmd,
- "show bgp evpn vni (1-16777215)",
- SHOW_STR
- BGP_STR
- "Address family modifier\n"
"Show VNI\n"
"VNI number\n")
{
- vni_t vni;
struct bgp *bgp;
+ vni_t vni;
+ int idx = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- vni = strtoul(argv[4]->arg, NULL, 10);
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ if (argc == ((idx + 1) + 1)) {
+ vty_out(vty, "Advertise gateway macip flag: %s\n",
+ bgp->advertise_gw_macip ? "Enabled" : "Disabled");
+
+ /* Display all VNIs */
+ vty_out(vty, "Advertise All VNI flag: %s\n",
+ bgp->advertise_all_vni ? "Enabled" : "Disabled");
+ evpn_show_all_vnis(vty, bgp);
+ } else {
+ /* Display specific VNI */
+ vni = strtoul(argv[argc - 1]->arg, NULL, 10);
+ evpn_show_vni(vty, bgp, vni);
+ }
- evpn_show_vni(vty, bgp, vni);
return CMD_SUCCESS;
}
-/* `show bgp evpn summary' commands. */
-DEFUN (show_bgp_evpn_summary,
- show_bgp_evpn_summary_cmd,
- "show bgp evpn summary [json]",
+/*
+ * Display EVPN neighbor summary.
+ */
+DEFUN (show_bgp_l2vpn_evpn_summary,
+ show_bgp_l2vpn_evpn_summary_cmd,
+ "show bgp l2vpn evpn summary [json]",
SHOW_STR
BGP_STR
- "EVPN\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
"Summary of BGP neighbor status\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj);
}
-/* Show bgp evpn route */
-DEFUN (show_bgp_evpn_route,
- show_bgp_evpn_route_cmd,
- "show bgp evpn route [type <macip|multicast>]",
+/*
+ * Display global EVPN routing table.
+ */
+DEFUN (show_bgp_l2vpn_evpn_route,
+ show_bgp_l2vpn_evpn_route_cmd,
+ "show bgp l2vpn evpn route [type <macip|multicast>]",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n")
{
struct bgp *bgp;
+ int idx = 0;
int type = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- if (argc == 6) {
- if (strncmp(argv[5]->arg, "ma", 2) == 0)
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ if (argc == ((idx + 1) + 3)) {
+ /* Specific type is requested */
+ if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE;
- else if (strncmp(argv[5]->arg, "mu", 2) == 0)
+ else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE;
else
return CMD_WARNING;
@@ -1828,13 +1958,17 @@ DEFUN (show_bgp_evpn_route,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_route_rd,
- show_bgp_evpn_route_rd_cmd,
- "show bgp evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
+/*
+ * Display global EVPN routing table for specific RD.
+ */
+DEFUN (show_bgp_l2vpn_evpn_route_rd,
+ show_bgp_l2vpn_evpn_route_rd_cmd,
+ "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"Route Distinguisher\n"
"ASN:XX or A.B.C.D:XX\n"
"Specify Route type\n"
@@ -1844,22 +1978,27 @@ DEFUN (show_bgp_evpn_route_rd,
struct bgp *bgp;
int ret;
struct prefix_rd prd;
+ int idx = 0;
int type = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- ret = str2prefix_rd(argv[5]->arg, &prd);
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ ret = str2prefix_rd(argv[idx + 3]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
- if (argc == 8) {
- if (strncmp(argv[7]->arg, "ma", 2) == 0)
+ if (argc == ((idx + 1) + 5)) {
+ /* Specific type is requested */
+ if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE;
- else if (strncmp(argv[7]->arg, "mu", 2) == 0)
+ else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE;
else
return CMD_WARNING;
@@ -1869,13 +2008,17 @@ DEFUN (show_bgp_evpn_route_rd,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_route_rd_macip,
- show_bgp_evpn_route_rd_macip_cmd,
- "show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
+/*
+ * Display global EVPN routing table for specific RD and MACIP.
+ */
+DEFUN (show_bgp_l2vpn_evpn_route_rd_macip,
+ show_bgp_l2vpn_evpn_route_rd_macip_cmd,
+ "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"Route Distinguisher\n"
"ASN:XX or A.B.C.D:XX\n"
"MAC\n"
@@ -1888,23 +2031,28 @@ DEFUN (show_bgp_evpn_route_rd_macip,
struct prefix_rd prd;
struct ethaddr mac;
struct ipaddr ip;
+ int idx = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- ret = str2prefix_rd(argv[5]->arg, &prd);
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ ret = str2prefix_rd(argv[idx + 3]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING;
}
- if (!prefix_str2mac(argv[7]->arg, &mac)) {
+ if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING;
}
memset(&ip, 0, sizeof(ip));
- if (argc == 10 && argv[9]->arg != NULL) {
- if (str2ipaddr(argv[9]->arg, &ip) != 0) {
+ if (argc == (idx + 1 + 7) && argv[argc - 1]->arg != NULL) {
+ /* Specific MAC+IP requested */
+ if (str2ipaddr(argv[argc - 1]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed IP address\n");
return CMD_WARNING;
}
@@ -1914,13 +2062,17 @@ DEFUN (show_bgp_evpn_route_rd_macip,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_route_vni,
- show_bgp_evpn_route_vni_cmd,
- "show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
+/*
+ * Display per-VNI EVPN routing table.
+ */
+DEFUN (show_bgp_l2vpn_evpn_route_vni,
+ show_bgp_l2vpn_evpn_route_vni_cmd,
+ "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"Specify Route type\n"
@@ -1933,25 +2085,29 @@ DEFUN (show_bgp_evpn_route_vni,
struct bgp *bgp;
struct in_addr vtep_ip;
int type = 0;
+ int idx = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
vtep_ip.s_addr = 0;
- vni = strtoul(argv[5]->arg, NULL, 10);
+ vni = strtoul(argv[idx + 3]->arg, NULL, 10);
- if (argc == 8 && argv[6]->arg) {
- if (strncmp(argv[6]->arg, "type", 4) == 0) {
- if (strncmp(argv[7]->arg, "ma", 2) == 0)
+ if (argc == (idx + 1 + 5) && argv[idx + 4]->arg) {
+ if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) {
+ if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE;
- else if (strncmp(argv[7]->arg, "mu", 2) == 0)
+ else if (strncmp(argv[idx + 5]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE;
else
return CMD_WARNING;
- } else if (strncmp(argv[6]->arg, "vtep", 4) == 0) {
- if (!inet_aton(argv[7]->arg, &vtep_ip)) {
+ } else if (strncmp(argv[idx + 4]->arg, "vtep", 4) == 0) {
+ if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
@@ -1963,13 +2119,17 @@ DEFUN (show_bgp_evpn_route_vni,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_route_vni_macip,
- show_bgp_evpn_route_vni_macip_cmd,
- "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]",
+/*
+ * Display per-VNI EVPN routing table for specific MACIP.
+ */
+DEFUN (show_bgp_l2vpn_evpn_route_vni_macip,
+ show_bgp_l2vpn_evpn_route_vni_macip_cmd,
+ "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD]",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"MAC\n"
@@ -1981,19 +2141,23 @@ DEFUN (show_bgp_evpn_route_vni_macip,
struct bgp *bgp;
struct ethaddr mac;
struct ipaddr ip;
+ int idx = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- vni = strtoul(argv[5]->arg, NULL, 10);
- if (!prefix_str2mac(argv[7]->arg, &mac)) {
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ vni = strtoul(argv[idx + 3]->arg, NULL, 10);
+ if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING;
}
memset(&ip, 0, sizeof(ip));
- if (argc == 10 && argv[9]->arg != NULL) {
- if (str2ipaddr(argv[9]->arg, &ip) != 0) {
+ if (argc == (idx + 1 + 7) && argv[idx + 7]->arg != NULL) {
+ if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed IP address\n");
return CMD_WARNING;
}
@@ -2003,13 +2167,17 @@ DEFUN (show_bgp_evpn_route_vni_macip,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_route_vni_multicast,
- show_bgp_evpn_route_vni_multicast_cmd,
- "show bgp evpn route vni (1-16777215) multicast A.B.C.D",
+/*
+ * Display per-VNI EVPN routing table for specific multicast IP (remote VTEP).
+ */
+DEFUN (show_bgp_l2vpn_evpn_route_vni_multicast,
+ show_bgp_l2vpn_evpn_route_vni_multicast_cmd,
+ "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"Multicast (Type-3) route\n"
@@ -2019,13 +2187,17 @@ DEFUN (show_bgp_evpn_route_vni_multicast,
struct bgp *bgp;
int ret;
struct in_addr orig_ip;
+ int idx = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
- vni = strtoul(argv[5]->arg, NULL, 10);
- ret = inet_aton(argv[7]->arg, &orig_ip);
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
+ vni = strtoul(argv[idx + 3]->arg, NULL, 10);
+ ret = inet_aton(argv[idx + 5]->arg, &orig_ip);
if (!ret) {
vty_out(vty, "%% Malformed Originating Router IP address\n");
return CMD_WARNING;
@@ -2035,13 +2207,17 @@ DEFUN (show_bgp_evpn_route_vni_multicast,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_route_vni_all,
- show_bgp_evpn_route_vni_all_cmd,
- "show bgp evpn route vni all [vtep A.B.C.D]",
+/*
+ * Display per-VNI EVPN routing table - for all VNIs.
+ */
+DEFUN (show_bgp_l2vpn_evpn_route_vni_all,
+ show_bgp_l2vpn_evpn_route_vni_all_cmd,
+ "show bgp l2vpn evpn route vni all [vtep A.B.C.D]",
SHOW_STR
BGP_STR
- "Address Family Modifier\n"
- "Display EVPN route information\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "EVPN route information\n"
"VXLAN Network Identifier\n"
"All VNIs\n"
"Remote VTEP\n"
@@ -2049,14 +2225,18 @@ DEFUN (show_bgp_evpn_route_vni_all,
{
struct bgp *bgp;
struct in_addr vtep_ip;
+ int idx = 0;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
+ if (!argv_find(argv, argc, "evpn", &idx))
+ return CMD_WARNING;
+
vtep_ip.s_addr = 0;
- if (argc == 8 && argv[7]->arg) {
- if (!inet_aton(argv[7]->arg, &vtep_ip)) {
+ if (argc == (idx + 1 + 5) && argv[idx + 5]->arg) {
+ if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
@@ -2066,12 +2246,16 @@ DEFUN (show_bgp_evpn_route_vni_all,
return CMD_SUCCESS;
}
-DEFUN (show_bgp_evpn_import_rt,
- show_bgp_evpn_import_rt_cmd,
- "show bgp evpn import-rt",
+/*
+ * Display EVPN import route-target hash table
+ */
+DEFUN (show_bgp_l2vpn_evpn_import_rt,
+ show_bgp_l2vpn_evpn_import_rt_cmd,
+ "show bgp l2vpn evpn import-rt",
SHOW_STR
BGP_STR
- "Address family modifier\n"
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
"Show import route target\n")
{
struct bgp *bgp;
@@ -2084,6 +2268,97 @@ DEFUN (show_bgp_evpn_import_rt,
return CMD_SUCCESS;
}
+#if defined(HAVE_CUMULUS)
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd,
+ "show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR
+ "Show VNI\n"
+ "VNI number\n")
+
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd,
+ "show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR
+ "Summary of BGP neighbor status\n"
+ JSON_STR)
+
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd,
+ "show bgp evpn route [type <macip|multicast>]",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "Specify Route type\n"
+ "MAC-IP (Type-2) route\n"
+ "Multicast (Type-3) route\n")
+
+ALIAS_HIDDEN(
+ show_bgp_l2vpn_evpn_route_rd, show_bgp_evpn_route_rd_cmd,
+ "show bgp evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "Route Distinguisher\n"
+ "ASN:XX or A.B.C.D:XX\n"
+ "Specify Route type\n"
+ "MAC-IP (Type-2) route\n"
+ "Multicast (Type-3) route\n")
+
+ALIAS_HIDDEN(
+ show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_evpn_route_rd_macip_cmd,
+ "show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "Route Distinguisher\n"
+ "ASN:XX or A.B.C.D:XX\n"
+ "MAC\n"
+ "MAC address (e.g., 00:e0:ec:20:12:62)\n"
+ "IP\n"
+ "IP address (IPv4 or IPv6)\n")
+
+ALIAS_HIDDEN(
+ show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd,
+ "show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "VNI number\n"
+ "Specify Route type\n"
+ "MAC-IP (Type-2) route\n"
+ "Multicast (Type-3) route\n"
+ "Remote VTEP\n"
+ "Remote VTEP IP address\n")
+
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip,
+ show_bgp_evpn_route_vni_macip_cmd,
+ "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "VNI number\n"
+ "MAC\n"
+ "MAC address (e.g., 00:e0:ec:20:12:62)\n"
+ "IP\n"
+ "IP address (IPv4 or IPv6)\n")
+
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast,
+ show_bgp_evpn_route_vni_multicast_cmd,
+ "show bgp evpn route vni (1-16777215) multicast A.B.C.D",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "VNI number\n"
+ "Multicast (Type-3) route\n"
+ "Originating Router IP address\n")
+
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
+ "show bgp evpn route vni all [vtep A.B.C.D]",
+ SHOW_STR BGP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "VXLAN Network Identifier\n"
+ "All VNIs\n"
+ "Remote VTEP\n"
+ "Remote VTEP IP address\n")
+
+ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd,
+ "show bgp evpn import-rt",
+ SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n")
+#endif
+
DEFUN_NOSH (bgp_evpn_vni,
bgp_evpn_vni_cmd,
"vni (1-16777215)",
@@ -2290,11 +2565,11 @@ DEFUN (bgp_evpn_vni_rt,
if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
ecomadd = ecommunity_str2com(argv[2]->arg,
ECOMMUNITY_ROUTE_TARGET, 0);
- ecommunity_str(ecomadd);
if (!ecomadd) {
vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING;
}
+ ecommunity_str(ecomadd);
/* Do nothing if we already have this import route-target */
if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd))
@@ -2305,11 +2580,11 @@ DEFUN (bgp_evpn_vni_rt,
if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
ecomadd = ecommunity_str2com(argv[2]->arg,
ECOMMUNITY_ROUTE_TARGET, 0);
- ecommunity_str(ecomadd);
if (!ecomadd) {
vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING;
}
+ ecommunity_str(ecomadd);
/* Do nothing if we already have this export route-target */
if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd))
@@ -2372,11 +2647,11 @@ DEFUN (no_bgp_evpn_vni_rt,
}
ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
- ecommunity_str(ecomdel);
if (!ecomdel) {
vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING;
}
+ ecommunity_str(ecomdel);
if (rt_type == RT_TYPE_IMPORT) {
if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
@@ -2484,6 +2759,11 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " advertise-all-vni\n");
}
+
+ if (bgp->advertise_gw_macip) {
+ bgp_config_write_family_header(vty, afi, safi, write);
+ vty_out(vty, " advertise-default-gw\n");
+ }
}
void bgp_ethernetvpn_init(void)
@@ -2509,10 +2789,24 @@ void bgp_ethernetvpn_init(void)
#if defined(HAVE_CUMULUS)
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
+ install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
+
+ /* "show bgp l2vpn evpn" commands. */
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
+ install_element(VIEW_NODE,
+ &show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
/* "show bgp evpn" commands. */
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
- install_element(VIEW_NODE, &show_bgp_evpn_vni_num_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_route_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd);
@@ -2532,5 +2826,9 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
+ install_element(BGP_EVPN_VNI_NODE,
+ &bgp_evpn_advertise_default_gw_vni_cmd);
+ install_element(BGP_EVPN_VNI_NODE,
+ &no_bgp_evpn_advertise_default_gw_vni_cmd);
#endif
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index e4e421510f..35f793f861 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1580,10 +1580,18 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
/* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME(filter) || (ri->extra && ri->extra->suppress)) {
struct bgp_info info;
+ struct bgp_info_extra dummy_info_extra;
struct attr dummy_attr;
info.peer = peer;
info.attr = attr;
+
+ if (ri->extra) {
+ memcpy(&dummy_info_extra, ri->extra,
+ sizeof(struct bgp_info_extra));
+ info.extra = &dummy_info_extra;
+ }
+
/* don't confuse inbound and outbound setting */
RESET_FLAG(attr->rmap_change_flags);
@@ -6238,6 +6246,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty)
} else
len += vty_out(vty, "/%d", p->prefixlen);
} else if (p->family == AF_ETHERNET) {
+ prefix2str(p, buf, PREFIX_STRLEN);
+ len = vty_out(vty, "%s", buf);
+ } else if (p->family == AF_EVPN) {
#if defined(HAVE_CUMULUS)
len = vty_out(vty, "%s",
bgp_evpn_route2str((struct prefix_evpn *)p, buf,
@@ -6505,15 +6516,14 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
len = vty_out(
vty, "%s",
binfo->peer->conf_if);
- len =
- 7 - len; /* len of IPv6
- addr + max
- len of def
- ifname */
+ len = 16 - len; /* len of IPv6
+ addr + max
+ len of def
+ ifname */
if (len < 1)
vty_out(vty, "\n%*s",
- 45, " ");
+ 36, " ");
else
vty_out(vty, "%*s", len,
" ");
@@ -6801,7 +6811,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
if (attr) {
if (((p->family == AF_INET)
&& ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
- || (safi == SAFI_EVPN && p->family == AF_ETHERNET
+ || (safi == SAFI_EVPN
&& !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
|| (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
@@ -6826,7 +6836,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
}
} else if (((p->family == AF_INET6)
&& ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
- || (safi == SAFI_EVPN && p->family == AF_ETHERNET
+ || (safi == SAFI_EVPN
&& BGP_ATTR_NEXTHOP_AFI_IP6(attr))
|| (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
char buf_a[BUFSIZ];
@@ -7326,7 +7336,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
/* Line2 display Next-hop, Neighbor, Router-id */
/* Display the nexthop */
- if ((p->family == AF_INET || p->family == AF_ETHERNET)
+ if ((p->family == AF_INET || p->family == AF_ETHERNET ||
+ p->family == AF_EVPN)
&& (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|| safi == SAFI_EVPN
|| !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
@@ -10232,6 +10243,10 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi,
enum bgp_show_type type, u_char use_json)
{
+ /* labeled-unicast routes live in the unicast table */
+ if (safi == SAFI_LABELED_UNICAST)
+ safi = SAFI_UNICAST;
+
if (!peer || !peer->afc[afi][safi]) {
if (use_json) {
json_object *json_no = NULL;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 285bb9a80c..a8e111d361 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -54,6 +54,9 @@
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_evpn_private.h"
+#include "bgpd/bgp_evpn_vty.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -572,6 +575,106 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
route_match_ip_route_source_prefix_list_compile,
route_match_ip_route_source_prefix_list_free};
+/* `match mac address MAC_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+ zero. */
+static route_map_result_t route_match_mac_address(void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+{
+ struct access_list *alist;
+ struct prefix p;
+
+ if (type == RMAP_BGP) {
+ alist = access_list_lookup(AFI_L2VPN, (char *)rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return RMAP_NOMATCH;
+
+ p.family = AF_ETHERNET;
+ p.prefixlen = ETH_ALEN * 8;
+ p.u.prefix_eth = prefix->u.prefix_evpn.mac;
+
+ return (access_list_apply(alist, &p)
+ == FILTER_DENY
+ ? RMAP_NOMATCH
+ : RMAP_MATCH);
+ }
+
+ return RMAP_NOMATCH;
+}
+
+/* Route map `mac address' match statement. `arg' should be
+ access-list name. */
+static void *route_match_mac_address_compile(const char *arg)
+{
+ return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+static void route_match_mac_address_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for mac address matching. */
+struct route_map_rule_cmd route_match_mac_address_cmd = {
+ "mac address", route_match_mac_address, route_match_mac_address_compile,
+ route_match_mac_address_free};
+
+/* `match vni' */
+
+/* Match function should return 1 if match is success else return
+ zero. */
+static route_map_result_t route_match_vni(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ vni_t vni = 0;
+ struct bgp_info *bgp_info = NULL;
+
+ if (type == RMAP_BGP) {
+ vni = *((vni_t *)rule);
+ bgp_info = (struct bgp_info *)object;
+
+ if (vni == label2vni(&bgp_info->extra->label))
+ return RMAP_MATCH;
+ }
+
+ return RMAP_NOMATCH;
+}
+
+/* Route map `vni' match statement. */
+static void *route_match_vni_compile(const char *arg)
+{
+ vni_t *vni = NULL;
+ char *end = NULL;
+
+ vni = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(vni_t));
+ if (!vni)
+ return NULL;
+
+ *vni = strtoul(arg, &end, 10);
+ if (*end != '\0')
+ return NULL;
+
+ return vni;
+}
+
+/* Free route map's compiled `vni' value. */
+static void route_match_vni_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for vni matching. */
+struct route_map_rule_cmd route_match_evpn_vni_cmd = {
+ "evpn vni", route_match_vni, route_match_vni_compile,
+ route_match_vni_free};
+
/* `match local-preference LOCAL-PREF' */
/* Match function return 1 if match is success else return zero. */
@@ -2994,6 +3097,55 @@ static void bgp_route_map_event(route_map_event_t event, const char *rmap_name)
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
+DEFUN (match_mac_address,
+ match_mac_address_cmd,
+ "match mac address WORD",
+ MATCH_STR
+ "mac address\n"
+ "Match address of route\n"
+ "MAC Access-list name\n")
+{
+ return bgp_route_match_add(vty, "mac address", argv[3]->arg,
+ RMAP_EVENT_FILTER_ADDED);
+}
+
+DEFUN (no_match_mac_address,
+ no_match_mac_address_cmd,
+ "no match mac address WORD",
+ NO_STR
+ MATCH_STR
+ "mac\n"
+ "Match address of route\n"
+ "MAC acess-list name\n")
+{
+ return bgp_route_match_delete(vty, "mac address", argv[4]->arg,
+ RMAP_EVENT_FILTER_DELETED);
+}
+
+DEFUN (match_evpn_vni,
+ match_evpn_vni_cmd,
+ "match evpn vni (1-16777215)",
+ MATCH_STR
+ EVPN_HELP_STR
+ "Match VNI\n"
+ "VNI ID\n")
+{
+ return bgp_route_match_add(vty, "evpn vni", argv[3]->arg,
+ RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_evpn_vni,
+ no_match_evpn_vni_cmd,
+ "no match evpn vni (1-16777215)",
+ NO_STR
+ MATCH_STR
+ EVPN_HELP_STR
+ "Match VNI\n"
+ "VNI ID\n")
+{
+ return bgp_route_match_delete(vty, "evpn vni", argv[4]->arg,
+ RMAP_EVENT_MATCH_DELETED);
+}
DEFUN (match_peer,
match_peer_cmd,
@@ -4351,6 +4503,8 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_probability_cmd);
route_map_install_match(&route_match_interface_cmd);
route_map_install_match(&route_match_tag_cmd);
+ route_map_install_match(&route_match_mac_address_cmd);
+ route_map_install_match(&route_match_evpn_vni_cmd);
route_map_install_set(&route_set_ip_nexthop_cmd);
route_map_install_set(&route_set_local_pref_cmd);
@@ -4381,6 +4535,10 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_match_ip_route_source_cmd);
install_element(RMAP_NODE, &match_ip_route_source_prefix_list_cmd);
install_element(RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd);
+ install_element(RMAP_NODE, &match_mac_address_cmd);
+ install_element(RMAP_NODE, &no_match_mac_address_cmd);
+ install_element(RMAP_NODE, &match_evpn_vni_cmd);
+ install_element(RMAP_NODE, &no_match_evpn_vni_cmd);
install_element(RMAP_NODE, &match_aspath_cmd);
install_element(RMAP_NODE, &no_match_aspath_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 0220a7e55d..01c27920f5 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -12047,6 +12047,8 @@ void bgp_vty_init(void)
install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd);
+ install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd);
/* "neighbor unsuppress-map" commands. */
install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 5071be909e..2fc75ea5a2 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2034,6 +2034,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0);
}
+int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
+{
+ struct stream *s = NULL;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ return 0;
+
+ /* Don't try to register if Zebra doesn't know of this instance. */
+ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ return 0;
+
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_ADVERTISE_DEFAULT_GW, bgp->vrf_id);
+ stream_putc(s, advertise);
+ stream_put3(s, vni);
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zclient_send_message(zclient);
+}
+
int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise)
{
struct stream *s;
@@ -2120,7 +2143,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
int ipa_len;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
- u_char sticky;
+ u_char flags;
memset(&ip, 0, sizeof(ip));
s = zclient->ibuf;
@@ -2140,21 +2163,20 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
(ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6;
stream_get(&ip.ip.addr, s, ipa_len);
}
- sticky = stream_getc(s);
+ flags = stream_getc(s);
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("%u:Recv MACIP %s %sMAC %s IP %s VNI %u", vrf_id,
- (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
- sticky ? "sticky " : "",
- prefix_mac2str(&mac, buf, sizeof(buf)),
+ zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u",
+ vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+ flags, prefix_mac2str(&mac, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
if (command == ZEBRA_MACIP_ADD)
- return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, sticky);
+ return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, flags);
else
return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
}
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 8e55eb6d8d..11405d1c1b 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -21,6 +21,8 @@
#ifndef _QUAGGA_BGP_ZEBRA_H
#define _QUAGGA_BGP_ZEBRA_H
+#include "vxlan.h"
+
extern void bgp_zebra_init(struct thread_master *master);
extern void bgp_zebra_destroy(void);
extern int bgp_if_update_all(void);
@@ -57,6 +59,7 @@ extern struct interface *if_lookup_by_ipv6(struct in6_addr *, ifindex_t,
extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t,
vrf_id_t);
+extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
extern int bgp_zebra_num_connects(void);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 208a4e4b4e..bfdddc69b1 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -380,6 +380,9 @@ struct bgp {
/* EVI hash table */
struct hash *vnihash;
+ /* EVPN enable - advertise gateway macip routes */
+ int advertise_gw_macip;
+
/* EVPN enable - advertise local VNIs and their MACs etc. */
int advertise_all_vni;
@@ -1488,7 +1491,8 @@ static inline int peer_group_af_configured(struct peer_group *group)
|| peer->afc[AFI_IP6][SAFI_MULTICAST]
|| peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP6][SAFI_MPLS_VPN]
- || peer->afc[AFI_IP6][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_EVPN])
+ || peer->afc[AFI_IP6][SAFI_ENCAP]
+ || peer->afc[AFI_L2VPN][SAFI_EVPN])
return 1;
return 0;
}
diff --git a/bgpd/rfapi/.gitignore b/bgpd/rfapi/.gitignore
deleted file mode 100644
index 0638d7514b..0000000000
--- a/bgpd/rfapi/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.dirstamp
diff --git a/configure.ac b/configure.ac
index 6b5cd19a5f..574992342f 100755
--- a/configure.ac
+++ b/configure.ac
@@ -9,6 +9,7 @@ AC_PREREQ(2.60)
AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
+AC_SUBST(PACKAGE_URL)
PACKAGE_FULLNAME="FRRouting"
AC_SUBST(PACKAGE_FULLNAME)
@@ -321,8 +322,6 @@ AC_ARG_ENABLE(snmp,
AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)]))
AC_ARG_WITH(libpam,
AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh]))
-AC_ARG_ENABLE(tcp-zebra,
- AS_HELP_STRING([--enable-tcp-zebra], [enable TCP/IP socket connection between zebra and protocol daemon]))
AC_ARG_ENABLE(ospfapi,
AS_HELP_STRING([--disable-ospfapi], [do not build OSPFAPI to access the OSPF LSA Database]))
AC_ARG_ENABLE(ospfclient,
@@ -559,10 +558,6 @@ AM_CONDITIONAL([HAVE_PROTOBUF], [test "x$have_protobuf" = "xyes"])
# End of logic for protobuf support.
#
-if test "${enable_tcp_zebra}" = "yes"; then
- AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication)
-fi
-
if test "${enable_linux24_tcp_md5}" = "yes"; then
AC_DEFINE(HAVE_TCP_MD5_LINUX24,,Old Linux 2.4 TCP MD5 Signature Patch)
fi
@@ -1025,6 +1020,13 @@ fi
LIBS="$TMPLIBS"
AC_SUBST(LIBM)
+AC_CHECK_FUNCS([ppoll], [
+ AC_DEFINE([HAVE_PPOLL], 1, [have Linux/BSD ppoll()])
+])
+AC_CHECK_FUNCS([pollts], [
+ AC_DEFINE([HAVE_POLLTS], 1, [have NetBSD pollts()])
+])
+
dnl ---------------
dnl other functions
dnl ---------------
@@ -1063,8 +1065,11 @@ case "$host_os" in
if test $ac_cv_header_net_bpf_h = no; then
if test $ac_cv_header_sys_dlpi_h = no; then
AC_MSG_RESULT(none)
+ if test "${enable_isisd}" = yes; then
+ AC_MSG_FAILURE([IS-IS support requested but no packet backend found])
+ fi
AC_MSG_WARN([*** IS-IS support will not be built ***])
- ISISD=""
+ enable_isisd="no"
else
AC_MSG_RESULT(DLPI)
fi
@@ -1247,27 +1252,13 @@ else
fi
AM_CONDITIONAL(BGPD, test "x$BGPD" = "xbgpd")
-if test "${enable_ripd}" = "no";then
- RIPD=""
-else
- RIPD="ripd"
-fi
-AM_CONDITIONAL(RIPD, test "x$RIPD" = "xripd")
-
-if test "${enable_ospfd}" = "no";then
- OSPFD=""
-else
- OSPFD="ospfd"
-fi
-AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd")
+AM_CONDITIONAL(RIPD, test "${enable_ripd}" != "no")
+AM_CONDITIONAL(OSPFD, test "${enable_ospfd}" != "no")
+AM_CONDITIONAL(LDPD, test "${enable_ldpd}" != "no")
-if test "${enable_ldpd}" = "no";then
- LDPD=""
-else
- LDPD="ldpd"
+AS_IF([test "${enable_ldpd}" != "no"], [
AC_DEFINE(HAVE_LDPD, 1, ldpd)
-fi
-AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd")
+])
NHRPD=""
case "$host_os" in
@@ -1284,12 +1275,7 @@ case "$host_os" in
esac
AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd")
-if test "${enable_eigrpd}" = "no";then
- EIGRPD=""
-else
- EIGRPD="eigrpd"
-fi
-AM_CONDITIONAL(EIGRPD, test "x$EIGRPD" = "xeigrpd")
+AM_CONDITIONAL(EIGRPD, test "${enable_eigrpd}" != "no")
if test "${enable_watchfrr}" = "no";then
WATCHFRR=""
@@ -1308,30 +1294,10 @@ if test "${enable_ospfapi}" != "no";then
fi
AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient")
-
-case "${enable_ripngd}" in
- "no" ) RIPNGD="";;
- * ) RIPNGD="ripngd";;
-esac
-AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd")
-
-case "${enable_babeld}" in
- "no" ) BABELD="";;
- * ) BABELD="babeld";;
-esac
-AM_CONDITIONAL(BABELD, test "x$BABELD" = "xbabeld")
-
-case "${enable_ospf6d}" in
- "no" ) OSPF6D="";;
- * ) OSPF6D="ospf6d";;
-esac
-AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d")
-
-case "${enable_isisd}" in
- "no" ) ISISD="";;
- * ) ISISD="isisd";;
-esac
-AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd")
+AM_CONDITIONAL(RIPNGD, test "${enable_ripngd}" != "no")
+AM_CONDITIONAL(BABELD, test "${enable_babeld}" != "no")
+AM_CONDITIONAL(OSPF6D, test "${enable_ospf6d}" != "no")
+AM_CONDITIONAL(ISISD, test "${enable_isisd}" != "no")
case "${enable_pimd}" in
"no" ) PIMD="";;
@@ -1370,23 +1336,13 @@ AC_SUBST(DOC)
AC_SUBST(RFPTEST)
AC_SUBST(LIBRFP)
AC_SUBST(RFPINC)
-AC_SUBST(BABELD)
AC_SUBST(BGPD)
-AC_SUBST(RIPD)
-AC_SUBST(RIPNGD)
-AC_SUBST(OSPFD)
-AC_SUBST(OSPF6D)
-AC_SUBST(LDPD)
-AC_SUBST(NHRPD)
-AC_SUBST(EIGRPD)
AC_SUBST(WATCHFRR)
AC_SUBST(ISISD)
AC_SUBST(PIMD)
AC_SUBST(SOLARIS)
AC_SUBST(VTYSH)
AC_SUBST(CURSES)
-AC_SUBST(OSPFCLIENT)
-AC_SUBST(OSPFAPI)
AC_CHECK_LIB(crypt, crypt, [],
[AC_CHECK_LIB(crypto, DES_crypt)])
AC_CHECK_LIB(resolv, res_init)
@@ -1830,15 +1786,12 @@ AC_CACHE_VAL(ac_cv_htonl_works,
)
AC_MSG_RESULT($ac_cv_htonl_works)
-AC_CONFIG_FILES([Makefile ripd/Makefile
- ripngd/Makefile bgpd/Makefile ospfd/Makefile watchfrr/Makefile
- ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
- doc/Makefile ospfclient/Makefile tests/Makefile
+AC_CONFIG_FILES([Makefile
+ bgpd/Makefile watchfrr/Makefile
+ vtysh/Makefile
+ doc/Makefile tests/Makefile
bgpd/rfp-example/rfptest/Makefile bgpd/rfp-example/librfp/Makefile
- babeld/Makefile
pimd/Makefile
- eigrpd/Makefile
- nhrpd/Makefile
tools/Makefile
redhat/frr.spec
snapcraft/snapcraft.yaml
@@ -1864,11 +1817,44 @@ AC_CONFIG_FILES([Makefile ripd/Makefile
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
pkgsrc/eigrpd.sh])
+if test "${enable_bgp_vnc}" != "no"; then
+ if test "${with_rfp_path}" != "bgpd/rfp-example" ; then
+ AC_CONFIG_FILES([${with_rfp_path}/rfptest/Makefile ${with_rfp_path}/librfp/Makefile])
+ fi
+fi
AC_CONFIG_FILES([solaris/Makefile])
AC_CONFIG_FILES([vtysh/extract.pl],[chmod +x vtysh/extract.pl])
+AC_CONFIG_COMMANDS([lib/route_types.h], [
+ dst="${ac_abs_top_builddir}/lib/route_types.h"
+ ${PERL} "${ac_abs_top_srcdir}/lib/route_types.pl" \
+ < "${ac_abs_top_srcdir}/lib/route_types.txt" \
+ > "${dst}.tmp"
+ test -f "${dst}" \
+ && diff "${dst}.tmp" "${dst}" >/dev/null 2>/dev/null \
+ && rm "${dst}.tmp" \
+ || mv "${dst}.tmp" "${dst}"
+], [
+ PERL="$PERL"
+])
+
+AS_IF([test "x$with_pkg_git_version" = "xyes"], [
+ AC_CONFIG_COMMANDS([lib/gitversion.h], [
+ dst="${ac_abs_top_builddir}/lib/gitversion.h"
+ ${PERL} "${ac_abs_top_srcdir}/lib/gitversion.pl" \
+ "${ac_abs_top_srcdir}" \
+ > "${dst}.tmp"
+ test -f "${dst}" \
+ && diff "${dst}.tmp" "${dst}" >/dev/null 2>/dev/null \
+ && rm "${dst}.tmp" \
+ || mv "${dst}.tmp" "${dst}"
+ ], [
+ PERL="$PERL"
+ ])
+])
+
## Hack, but working solution to avoid rebuilding of frr.info.
## It's already in CVS until texinfo 4.7 is more common.
AC_OUTPUT
diff --git a/debian/frr.logrotate b/debian/frr.logrotate
index 0dd68fb257..9a1fa2149b 100644
--- a/debian/frr.logrotate
+++ b/debian/frr.logrotate
@@ -7,11 +7,21 @@
create 640 frr frrvty
postrotate
- for i in zebra bgpd ripd ospfd ripngd ospf6d isisd pimd; do
- if [ -e /var/run/frr/$i.pid ] ; then
- kill -USR1 `cat /var/run/frr/$i.pid`
- fi
-
- done
+ pid=$(lsof -t -a -c /syslog/ /var/log/frr/* 2>/dev/null)
+ if [ -n "$pid" ]
+ then # using syslog
+ kill -HUP $pid
+ fi
+ # in case using file logging; if switching back and forth
+ # between file and syslog, rsyslogd might still have file
+ # open, as well as the daemons, so always signal the daemons.
+ # It's safe, a NOP if (only) syslog is being used.
+ for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd \
+ pimd ripd ripngd zebra ; do
+ if [ -e /var/run/frr/$i.pid ] ; then
+ pids="$pids $(cat /var/run/frr/$i.pid)"
+ fi
+ done
+ [ -n "$pids" ] && kill -USR1 $pids
endscript
}
diff --git a/doc/Building_FRR_on_CentOS6.md b/doc/Building_FRR_on_CentOS6.md
index b25845c38a..10830e5016 100644
--- a/doc/Building_FRR_on_CentOS6.md
+++ b/doc/Building_FRR_on_CentOS6.md
@@ -109,7 +109,6 @@ an example.)
--enable-rtadv \
--disable-exampledir \
--enable-watchfrr \
- --enable-tcp-zebra \
--disable-ldpd \
--enable-fpm \
--enable-nhrpd \
diff --git a/doc/Building_FRR_on_CentOS7.md b/doc/Building_FRR_on_CentOS7.md
index 932459167f..787b80fbf7 100644
--- a/doc/Building_FRR_on_CentOS7.md
+++ b/doc/Building_FRR_on_CentOS7.md
@@ -61,7 +61,6 @@ an example.)
--enable-rtadv \
--disable-exampledir \
--enable-watchfrr \
- --enable-tcp-zebra \
--disable-ldpd \
--enable-fpm \
--enable-nhrpd \
diff --git a/doc/Building_FRR_on_Debian8.md b/doc/Building_FRR_on_Debian8.md
index 1a961f752a..a2dbbdb30f 100644
--- a/doc/Building_FRR_on_Debian8.md
+++ b/doc/Building_FRR_on_Debian8.md
@@ -60,7 +60,6 @@ an example.)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--enable-ldpd \
--with-pkg-git-version \
diff --git a/doc/Building_FRR_on_Fedora24.md b/doc/Building_FRR_on_Fedora24.md
index c161b9b128..0070fd1534 100644
--- a/doc/Building_FRR_on_Fedora24.md
+++ b/doc/Building_FRR_on_Fedora24.md
@@ -54,7 +54,6 @@ an example.)
--enable-rtadv \
--disable-exampledir \
--enable-watchfrr \
- --enable-tcp-zebra \
--enable-ldpd \
--enable-fpm \
--enable-nhrpd \
diff --git a/doc/Building_FRR_on_FreeBSD10.md b/doc/Building_FRR_on_FreeBSD10.md
index 36ef573bb0..ccae83a667 100644
--- a/doc/Building_FRR_on_FreeBSD10.md
+++ b/doc/Building_FRR_on_FreeBSD10.md
@@ -61,7 +61,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_FreeBSD11.md b/doc/Building_FRR_on_FreeBSD11.md
index d6affd688b..71ccd149ff 100644
--- a/doc/Building_FRR_on_FreeBSD11.md
+++ b/doc/Building_FRR_on_FreeBSD11.md
@@ -61,7 +61,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_FreeBSD9.md b/doc/Building_FRR_on_FreeBSD9.md
index 41d3148ad7..8a09d8a4cc 100644
--- a/doc/Building_FRR_on_FreeBSD9.md
+++ b/doc/Building_FRR_on_FreeBSD9.md
@@ -69,7 +69,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_NetBSD6.md b/doc/Building_FRR_on_NetBSD6.md
index 2e453da66c..4fe7109bcd 100644
--- a/doc/Building_FRR_on_NetBSD6.md
+++ b/doc/Building_FRR_on_NetBSD6.md
@@ -65,7 +65,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_NetBSD7.md b/doc/Building_FRR_on_NetBSD7.md
index f5f99d9ba0..7fe9ad20c9 100644
--- a/doc/Building_FRR_on_NetBSD7.md
+++ b/doc/Building_FRR_on_NetBSD7.md
@@ -59,7 +59,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_OmniOS.md b/doc/Building_FRR_on_OmniOS.md
index 7e75bda9e9..6e4575f07b 100644
--- a/doc/Building_FRR_on_OmniOS.md
+++ b/doc/Building_FRR_on_OmniOS.md
@@ -104,7 +104,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_OpenBSD6.md b/doc/Building_FRR_on_OpenBSD6.md
index e9e1030515..c1bfa5005e 100644
--- a/doc/Building_FRR_on_OpenBSD6.md
+++ b/doc/Building_FRR_on_OpenBSD6.md
@@ -54,7 +54,6 @@ an example)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_Ubuntu1204.md b/doc/Building_FRR_on_Ubuntu1204.md
index e8567867cc..58aa167d57 100644
--- a/doc/Building_FRR_on_Ubuntu1204.md
+++ b/doc/Building_FRR_on_Ubuntu1204.md
@@ -93,7 +93,6 @@ an example.)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--with-pkg-git-version \
--with-pkg-extra-version=-MyOwnFRRVersion
diff --git a/doc/Building_FRR_on_Ubuntu1404.md b/doc/Building_FRR_on_Ubuntu1404.md
index a0f3a121ff..8e6b38cc2d 100644
--- a/doc/Building_FRR_on_Ubuntu1404.md
+++ b/doc/Building_FRR_on_Ubuntu1404.md
@@ -53,7 +53,6 @@ an example.)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--enable-ldpd \
--with-pkg-git-version \
diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md
index 9144d4610b..a178f9a160 100644
--- a/doc/Building_FRR_on_Ubuntu1604.md
+++ b/doc/Building_FRR_on_Ubuntu1604.md
@@ -54,7 +54,6 @@ an example.)
--enable-configfile-mask=0640 \
--enable-logfile-mask=0640 \
--enable-rtadv \
- --enable-tcp-zebra \
--enable-fpm \
--enable-systemd=yes \
--with-pkg-git-version \
diff --git a/doc/Makefile.am b/doc/Makefile.am
index b2bdf91cd4..9016df7372 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -45,17 +45,19 @@ figures_txt = $(figures_names_parts:%=fig%.txt)
# provided by automake. If you are an automake wizard, please feel free to
# compact it somehow.
-# Built from defines.texi.in
-BUILT_SOURCES = defines.texi
-
info_TEXINFOS = frr.texi
# Have to manually specify the frr.pdf rule in order to allow
# us to have a generic automatic .pdf rule to build the figure sources
# because it cant just work from the png's directly it seems - contrary
# to the documentation...
-frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS)
- $(TEXI2PDF) -o "$@" $< || true
+frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS) defines.texi
+ $(TEXI2PDF) -o "$@" $<
+
+# don't ask me why the info file is in srcdir
+$(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi
+frr.dvi: $(frr_TEXINFOS) defines.texi
+frr.html: $(frr_TEXINFOS) defines.texi
frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \
vnc.texi \
@@ -65,7 +67,7 @@ frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \
eigrpd.texi \
ospf6d.texi ospfd.texi \
overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \
- snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \
+ snmp.texi vtysh.texi routeserver.texi $(figures_png) \
snmptrap.texi ospf_fundamentals.texi isisd.texi $(figures_txt)
.png.eps:
diff --git a/doc/basic.texi b/doc/basic.texi
index 05d72bc80f..6e43210bb8 100644
--- a/doc/basic.texi
+++ b/doc/basic.texi
@@ -450,7 +450,7 @@ Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
-Hello, this is @value{PACKAGE_NAME} (version @value{VERSION})
+Hello, this is @value{PACKAGE_NAME} (version @value{PACKAGE_VERSION})
@value{COPYRIGHT_STR}
User Access Verification
diff --git a/doc/bgpd.texi b/doc/bgpd.texi
index 8e0da12949..d6b07a270f 100644
--- a/doc/bgpd.texi
+++ b/doc/bgpd.texi
@@ -698,8 +698,11 @@ This command is deprecated and may be removed in a future release. Its
use should be avoided.
@end deffn
-@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {}
-@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {}
+@c for some reason, using [all] here triggers a bug in texinfo...
+@deffn {BGP} {neighbor @var{peer} next-hop-self} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {}
+@deffnx {BGP} {neighbor @var{peer} next-hop-self all} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self all} {}
This command specifies an announced route's nexthop as being equivalent
to the address of the bgp router if it is learned via eBGP.
If the optional keyword @code{all} is specified the modifiation is done
diff --git a/doc/defines.texi.in b/doc/defines.texi.in
index 0fadba964a..b2af89e40a 100644
--- a/doc/defines.texi.in
+++ b/doc/defines.texi.in
@@ -5,6 +5,8 @@
@set PACKAGE_NAME @PACKAGE_NAME@
@set PACKAGE_TARNAME @PACKAGE_TARNAME@
@set PACKAGE_STRING @PACKAGE_STRING@
+@set PACKAGE_URL @PACKAGE_URL@
+@set PACKAGE_VERSION @PACKAGE_VERSION@
@set AUTHORS Kunihiro Ishiguro, et al.
@set COPYRIGHT_YEAR 1999-2005
@set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS}
diff --git a/doc/frr.texi b/doc/frr.texi
index b08bb6fd04..d268b4b981 100644
--- a/doc/frr.texi
+++ b/doc/frr.texi
@@ -7,13 +7,9 @@
@setfilename frr.info
@c Set variables - sourced from defines.texi
@include defines.texi
-@settitle @uref{http://www.frrouting.org,,@value{PACKAGE_NAME}}
+@settitle @uref{@value{PACKAGE_URL},,@value{PACKAGE_NAME}}
@c %**end of header
-@c automake will automatically generate version.texi
-@c and set EDITION, VERSION, UPDATED and UPDATED-MONTH
-@include version.texi
-
@copying
@value{COPYRIGHT_STR}
@quotation
@@ -44,21 +40,18 @@ approved by Kunihiro Ishiguro.
@c @smallbook
@ifinfo
-This file documents the Frr Software Routing Suite which manages common
-TCP/IP routing protocols.
+This file documents the @uref{@value{PACKAGE_URL},,Frr Software Routing Suite}
+which manages common TCP/IP routing protocols.
-This is Edition @value{EDITION}, last updated @value{UPDATED} of
-@cite{The Frr Manual}, for @uref{http://www.frrouting.org/,,@value{PACKAGE_NAME}}
-Version @value{VERSION}.
+This document was generated for version @value{PACKAGE_VERSION}.
@insertcopying
@end ifinfo
@titlepage
-@title @uref{http://www.frrouting.org,,Frr}
+@title @uref{@value{PACKAGE_URL},,Frr}
@subtitle A routing software package for TCP/IP networks
-@subtitle @uref{http://www.frrouting.org,,@value{PACKAGE_NAME}} @value{VERSION}
-@subtitle @value{UPDATED-MONTH}
+@subtitle @uref{@value{PACKAGE_URL},,@value{PACKAGE_NAME}} @value{PACKAGE_VERSION}
@author @value{AUTHORS}
@page
@@ -72,9 +65,9 @@ Version @value{VERSION}.
@node Top
@top Frr -- With Virtual Network Control
-@uref{http://www.frrouting.org,,Frr} is an advanced routing software package
+@uref{@value{PACKAGE_URL},,Frr} is an advanced routing software package
that provides a suite of TCP/IP based routing protocols. This is the Manual
-for @value{PACKAGE_STRING}. @uref{http://www.frrouting.org,,Frr} is a fork of
+for @value{PACKAGE_STRING}. @uref{@value{PACKAGE_URL},,Frr} is a fork of
@uref{http://www.quagga.net,,Quagga}.
@insertcopying
diff --git a/doc/overview.texi b/doc/overview.texi
index 7ecf3d95c3..c988e219b7 100644
--- a/doc/overview.texi
+++ b/doc/overview.texi
@@ -2,7 +2,7 @@
@chapter Overview
@cindex Overview
- @uref{http://www.frrouting.org,,Frr} is a routing software package that
+ @uref{@value{PACKAGE_URL},,Frr} is a routing software package that
provides TCP/IP based routing services with routing protocols support such
as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (@pxref{Supported
RFCs}). Frr also supports special BGP Route Reflector and Route Server
@@ -275,12 +275,12 @@ November 1995.}
The official Frr web-site is located at:
-@uref{http://www.frrouting.org/}
+@uref{@value{PACKAGE_URL}}
and contains further information, as well as links to additional
resources.
-@uref{http://www.frrouting.org/,Frr} is a fork of Quagga, whose
+@uref{@value{PACKAGE_URL},Frr} is a fork of Quagga, whose
web-site is located at:
@uref{http://www.quagga.net/}.
@@ -296,12 +296,12 @@ web-site is located at:
There is a mailing list for discussions about Frr. If you have any
comments or suggestions to Frr, please subscribe to:
-@uref{http://lists.nox.tf/listinfo/frr-users}.
+@uref{https://lists.frrouting.org/listinfo/frog}.
-The @uref{http://www.frrouting.org/,,Frr} site has further information on
+The @uref{@value{PACKAGE_URL},,Frr} site has further information on
the available mailing lists, see:
- @uref{http://lists.nox.tf/lists.php}
+ @uref{https://lists.frrouting.org/}
@node Bug Reports
@section Bug Reports
diff --git a/doc/pimd.8.in b/doc/pimd.8.in
index 3fb060e564..6db3418f8f 100644
--- a/doc/pimd.8.in
+++ b/doc/pimd.8.in
@@ -60,7 +60,9 @@ restart pimd. The default is \fB\fI@CFG_STATE@/pimd.pid\fR.
.TP
\fB\-z\fR, \fB\-\-socket \fR\fIpath\fR
Specify the socket path for contacting the zebra daemon.
-The default is \fB\fI@CFG_STATE@/zserv.api\fR.
+The default is \fB\fI@CFG_STATE@/zserv.api\fR. The value of this option
+must be the same as the one given when starting zebra. Refer to the \fBzebra
+(8)\fR man page for more information.
.TP
\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR
Specify the port that the pimd VTY will listen on. This defaults to
diff --git a/doc/watchfrr.8.in b/doc/watchfrr.8.in
index 82098e1b0d..782ac7b46e 100644
--- a/doc/watchfrr.8.in
+++ b/doc/watchfrr.8.in
@@ -20,59 +20,6 @@ daemon's VTY UNIX stream socket, and send echo commands to ensure the
daemon responds. When the daemon crashes, EOF is received from the socket,
so that watchfrr can react immediately.
.PP
-This program can run in one of the following 5 modes:
-.TP
-.B Mode 0: monitor
-In this mode, the program serves as a monitor and reports status changes.
-.IP
-Example usage: watchfrr \-d zebra ospfd bgpd
-.TP
-.B Mode 1: global restart
-In this mode, whenever a daemon hangs or crashes, the given command is used
-to restart all watched daemons.
-.IP
-Example usage: watchfrr \-dz \e
-.br
--R '/sbin/service zebra restart; /sbin/service ospfd restart' \e
-.br
-zebra ospfd
-.TP
-.B Mode 2: individual daemon restart
-In this mode, whenever a single daemon hangs or crashes, the given command
-is used to restart this daemon only.
-.IP
-Example usage: watchfrr \-dz \-r '/sbin/service %s restart' \e
-.br
-zebra ospfd bgpd
-.TP
-.B Mode 3: phased zebra restart
-In this mode, whenever a single daemon hangs or crashes, the given command
-is used to restart this daemon only. The only exception is the zebra
-daemon; in this case, the following steps are taken: (1) all other daemons
-are stopped, (2) zebra is restarted, and (3) other daemons are started
-again.
-.IP
-Example usage: watchfrr \-adz \-r '/sbin/service %s restart' \e
-.br
-\-s '/sbin/service %s start' \e
-.br
-\-k '/sbin/service %s stop' zebra ospfd bgpd
-.TP
-.B Mode 4: phased global restart for any failure
-In this mode, whenever a single daemon hangs or crashes, the following
-steps are taken: (1) all other daemons are stopped, (2) zebra is restarted,
-and (3) other daemons are started again.
-.IP
-Example usage: watchfrr \-Adz \-r '/sbin/service %s restart' \e
-.br
-\-s '/sbin/service %s start' \e
-.br
-\-k '/sbin/service %s stop' zebra ospfd bgpd
-.PP
-Important: It is believed that mode 2 (individual daemon restart) is not
-safe, and mode 3 (phased zebra restart) may not be safe with certain
-routing daemons.
-.PP
In order to avoid restarting the daemons in quick succession, you can
supply the
.B \-m
@@ -87,6 +34,36 @@ the restart delay is set to the value of
otherwise the interval is doubled (but capped at the value of
.BR \-M ).
.SH OPTIONS
+The following 3 options specify scripts that
+.B watchfrr
+uses to perform start/stop/restart actions. These options are mandatory
+unless the
+.B --dry
+option is used:
+.TP
+.BI \-s " command" "\fR, \fB\-\-start\-command " command
+Supply a Bourne shell
+.I command
+to start a single daemon. The command string should contain the '%s'
+placeholder to be substituted with the daemon name.
+.TP
+.BI \-k " command" "\fR, \fB\-\-kill\-command " command
+Supply a Bourne shell
+.I command
+to stop a single daemon. The command string should contain the '%s'
+placeholder to be substituted with the daemon name.
+.TP
+.BI \-r " command" "\fR, \fB\-\-restart " command
+Supply a Bourne shell
+.I command
+to restart a single daemon. The command string should contain the '%s'
+placeholder to be substituted with the daemon name.
+.PP
+Other options:
+.TP
+.BI \-\-dry
+Run watchfrr in "dry-run" mode, only monitoring the specified daemons but not
+performing any start/stop/restart actions.
.TP
.BR \-d ", " \-\-daemon
Run in daemon mode. When supplied, error messages are sent to Syslog
@@ -97,10 +74,6 @@ Set the VTY socket
.I directory
(the default value is "/var/run/frr").
.TP
-.BR \-e ", " \-\-no\-echo
-Do not ping the daemons to test whether they respond. This option is
-necessary if one or more daemons do not support the echo command.
-.TP
.BI \-l " level" "\fR, \fB\-\-loglevel " level
Set the logging
.I level
@@ -131,68 +104,6 @@ Set the restart (kill) timeout in seconds (the default value is "20"). If
any background jobs are still running after this period has elapsed, they
will be killed.
.TP
-.BI \-r " command" "\fR, \fB\-\-restart " command
-Supply a Bourne shell
-.I command
-to restart a single daemon. The command string should contain the '%s'
-placeholder to be substituted with the daemon name.
-.IP
-Note that
-.B \-r
-and
-.B \-R
-options are not compatible.
-.TP
-.BI \-s " command" "\fR, \fB\-\-start\-command " command
-Supply a Bourne shell
-.I command
-to start a single daemon. The command string should contain the '%s'
-placeholder to be substituted with the daemon name.
-.TP
-.BI \-k " command" "\fR, \fB\-\-kill\-command " command
-Supply a Bourne shell
-.I command
-to stop a single daemon. The command string should contain the '%s'
-placeholder to be substituted with the daemon name.
-.TP
-.BR \-R ", " \-\-restart\-all
-When one or more daemons are shut down, try to restart them using the
-Bourne shell command supplied on the command line.
-.IP
-Note that
-.B \-r
-and
-.B \-R
-options are not compatible.
-.TP
-.BR \-z ", " \-\-unresponsive\-restart
-When a daemon is in an unresponsive state, treat it as being shut down for
-the restart purposes.
-.TP
-.BR \-a ", " \-\-all\-restart
-When zebra hangs or crashes, restart all daemons taking the following
-steps: (1) stop all other daemons, (2) restart zebra, and (3) start other
-daemons again.
-.IP
-Note that this option also requires
-.BR \-r ,
-.BR \-s ,
-and
-.B \-k
-options to be specified.
-.TP
-.BR \-A ", " \-\-always\-all\-restart
-When any daemon (i.e., not just zebra) hangs or crashes, restart all
-daemons taking the following steps: (1) stop all other daemons, (2) restart
-zebra, and (3) start other daemons again.
-.IP
-Note that this option also requires
-.BR \-r ,
-.BR \-s ,
-and
-.B \-k
-options to be specified.
-.TP
.BI \-p " filename" "\fR, \fB\-\-pid\-file " filename
Set the process identifier
.I filename
@@ -204,9 +115,8 @@ When the supplied
is found in any of the command line option arguments (i.e.,
.BR \-r ,
.BR \-s ,
-.BR \-k ,
or
-.BR \-R ),
+.BR \-k ),
replace it with a space.
.IP
This is an ugly hack to circumvent problems with passing the command line
@@ -217,6 +127,20 @@ Display the version information and exit.
.TP
.BR \-h ", " \-\-help
Display the usage information and exit.
+.SH PREVIOUS OPTIONS
+Prior versions of \fBwatchfrr\fR supported some additional options that no
+longer exist:
+.IP
+.BR \-a ,\ \-A ,\ \-e ,\ \-R ,\ \-z
+.PP
+The \fB-a\fR, \fB-A\fR and \fB-R\fR options were used to select alternate
+monitoring modes that offered different patterns of restarting daemons. The
+"correct" mode (phased restart) is now the default. The \fB-e\fR and \fB-z\fR
+options used to disable some monitoring aspects, watchfrr now always has all
+monitoring features enabled.
+.PP
+Removing these options should result in correct operation, if it does not
+please file a bug report.
.SH SEE ALSO
.BR zebra (8),
.BR bgpd (8),
diff --git a/doc/zebra.8.in b/doc/zebra.8.in
index f5b8bd4d80..7f4a81b1a0 100644
--- a/doc/zebra.8.in
+++ b/doc/zebra.8.in
@@ -26,6 +26,9 @@ zebra \- a routing manager for use with associated @PACKAGE_FULLNAME@ components
] [
.B \-M
.I module:options
+] [
+.B \-z
+.I socketpath
]
.SH DESCRIPTION
.B zebra
@@ -97,6 +100,11 @@ respectively. The \fBfpm\fR module takes an additional colon-separated
argument specifying the encapsulation, either \fBnetlink\fR or \fBprotobuf\fR.
It should thus be loaded with \fB-M fpm:netlink\fR or \fB-M fpm:protobuf\fR.
.TP
+\fB\-z\fR, \fB\-\-socket \fR\fIsocketpath\fR
+Use the specified path to open the zebra API socket on.
+The default is \fB\fI@CFG_STATE@/zserv.api\fR. This option must be given with
+the same value to all FRR protocol daemons.
+.TP
\fB\-v\fR, \fB\-\-version\fR
Print the version and exit.
.SH FILES
diff --git a/eigrpd/.gitignore b/eigrpd/.gitignore
index cd46e50c6c..5b72399e72 100644
--- a/eigrpd/.gitignore
+++ b/eigrpd/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
*.a
diff --git a/eigrpd/Makefile b/eigrpd/Makefile
new file mode 100644
index 0000000000..b6d60764e9
--- /dev/null
+++ b/eigrpd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. eigrpd/eigrpd
+%: ALWAYS
+ @$(MAKE) -s -C .. eigrpd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/eigrpd/Makefile.am b/eigrpd/Makefile.am
deleted file mode 100644
index 9ee792e552..0000000000
--- a/eigrpd/Makefile.am
+++ /dev/null
@@ -1,46 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(WERROR)
-
-noinst_LIBRARIES = libeigrp.a
-sbin_PROGRAMS = eigrpd
-
-libeigrp_a_SOURCES = \
- eigrpd.c eigrp_zebra.c \
- eigrp_interface.c eigrp_neighbor.c \
- eigrp_dump.c eigrp_vty.c \
- eigrp_network.c eigrp_packet.c \
- eigrp_topology.c eigrp_fsm.c \
- eigrp_hello.c eigrp_update.c \
- eigrp_query.c eigrp_reply.c \
- eigrp_snmp.c eigrp_siaquery.c \
- eigrp_siareply.c eigrp_filter.c \
- eigrp_memory.c
-
-
-eigrpdheaderdir = $(pkgincludedir)/eigrpd
-
-eigrpdheader_HEADERS = \
- eigrp_topology.h eigrp_dump.h eigrpd.h
-
-noinst_HEADERS = \
- eigrp_const.h eigrp_structs.h \
- eigrp_macros.h eigrp_interface.h \
- eigrp_neighbor.h eigrp_network.h \
- eigrp_packet.h eigrp_memory.h \
- eigrp_zebra.h eigrp_vty.h \
- eigrp_snmp.h eigrp_filter.h \
- eigrp_fsm.h
-
-eigrpd_SOURCES = eigrp_main.c $(libeigrp_a_SOURCES)
-
-eigrpd_LDADD = ../lib/libfrr.la @LIBCAP@
-
-EXTRA_DIST = EIGRP-MIB.txt
-
-examplesdir = $(exampledir)
-dist_examples_DATA = eigrpd.conf.sample
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index 15a8a71cf3..db5e38d422 100644
--- a/eigrpd/eigrp_dump.c
+++ b/eigrpd/eigrp_dump.c
@@ -616,5 +616,6 @@ void eigrp_debug_init()
install_element(CONFIG_NODE, &show_debugging_eigrp_cmd);
install_element(CONFIG_NODE, &debug_eigrp_packets_all_cmd);
install_element(CONFIG_NODE, &no_debug_eigrp_packets_all_cmd);
+ install_element(CONFIG_NODE, &debug_eigrp_transmit_cmd);
install_element(CONFIG_NODE, &no_debug_eigrp_transmit_cmd);
}
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
new file mode 100644
index 0000000000..2c6b1e321b
--- /dev/null
+++ b/eigrpd/subdir.am
@@ -0,0 +1,59 @@
+#
+# eigrpd
+#
+
+if EIGRPD
+noinst_LIBRARIES += eigrpd/libeigrp.a
+sbin_PROGRAMS += eigrpd/eigrpd
+dist_examples_DATA += eigrpd/eigrpd.conf.sample
+endif
+
+eigrpd_libeigrp_a_SOURCES = \
+ eigrpd/eigrp_dump.c \
+ eigrpd/eigrp_filter.c \
+ eigrpd/eigrp_fsm.c \
+ eigrpd/eigrp_hello.c \
+ eigrpd/eigrp_interface.c \
+ eigrpd/eigrp_memory.c \
+ eigrpd/eigrp_neighbor.c \
+ eigrpd/eigrp_network.c \
+ eigrpd/eigrp_packet.c \
+ eigrpd/eigrp_query.c \
+ eigrpd/eigrp_reply.c \
+ eigrpd/eigrp_siaquery.c \
+ eigrpd/eigrp_siareply.c \
+ eigrpd/eigrp_snmp.c \
+ eigrpd/eigrp_topology.c \
+ eigrpd/eigrp_update.c \
+ eigrpd/eigrp_vty.c \
+ eigrpd/eigrp_zebra.c \
+ eigrpd/eigrpd.c \
+ # end
+
+eigrpdheaderdir = $(pkgincludedir)/eigrpd
+eigrpdheader_HEADERS = \
+ eigrpd/eigrp_dump.h \
+ eigrpd/eigrp_topology.h \
+ eigrpd/eigrpd.h \
+ # end
+
+noinst_HEADERS += \
+ eigrpd/eigrp_const.h \
+ eigrpd/eigrp_filter.h \
+ eigrpd/eigrp_fsm.h \
+ eigrpd/eigrp_interface.h \
+ eigrpd/eigrp_macros.h \
+ eigrpd/eigrp_memory.h \
+ eigrpd/eigrp_neighbor.h \
+ eigrpd/eigrp_network.h \
+ eigrpd/eigrp_packet.h \
+ eigrpd/eigrp_snmp.h \
+ eigrpd/eigrp_structs.h \
+ eigrpd/eigrp_vty.h \
+ eigrpd/eigrp_zebra.h \
+ # end
+
+eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c
+eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la @LIBCAP@
+
+EXTRA_DIST += eigrpd/EIGRP-MIB.txt
diff --git a/fpm/subdir.am b/fpm/subdir.am
index f81a84222c..795535596b 100644
--- a/fpm/subdir.am
+++ b/fpm/subdir.am
@@ -13,7 +13,6 @@ fpm_libfrrfpm_pb_la_SOURCES = \
if HAVE_PROTOBUF
nodist_fpm_libfrrfpm_pb_la_SOURCES = fpm/fpm.pb-c.c
-BUILT_SOURCES += fpm/fpm.pb-c.c
CLEANFILES += \
fpm/fpm.pb-c.c \
fpm/fpm.pb-c.h \
diff --git a/isisd/.gitignore b/isisd/.gitignore
index 5e8028c2a6..a882bbf675 100644
--- a/isisd/.gitignore
+++ b/isisd/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
isisd
diff --git a/isisd/Makefile b/isisd/Makefile
new file mode 100644
index 0000000000..db3b70eead
--- /dev/null
+++ b/isisd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. isisd/isisd
+%: ALWAYS
+ @$(MAKE) -s -C .. isisd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/isisd/Makefile.am b/isisd/Makefile.am
deleted file mode 100644
index dc3d3683a1..0000000000
--- a/isisd/Makefile.am
+++ /dev/null
@@ -1,39 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-LIBS = @LIBS@
-
-AM_CFLAGS = $(WERROR)
-
-noinst_LIBRARIES = libisis.a
-sbin_PROGRAMS = isisd
-
-libisis_a_SOURCES = \
- isis_memory.c \
- isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \
- isisd.c isis_misc.c isis_zebra.c isis_dr.c \
- isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
- isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
- isis_vty.c isis_mt.c \
- isis_tlvs.c
-
-
-noinst_HEADERS = \
- isis_memory.h \
- isisd.h isis_pdu.h isis_adjacency.h isis_constants.h \
- isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
- isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
- iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
- isis_route.h isis_routemap.h isis_te.h isis_mt.h \
- isis_tlvs.h
-
-isisd_SOURCES = \
- isis_main.c $(libisis_a_SOURCES) \
- isis_bpf.c isis_dlpi.c isis_pfpacket.c
-
-isisd_LDADD = ../lib/libfrr.la @LIBCAP@
-
-examplesdir = $(exampledir)
-dist_examples_DATA = isisd.conf.sample
diff --git a/isisd/subdir.am b/isisd/subdir.am
new file mode 100644
index 0000000000..6e49d4ec80
--- /dev/null
+++ b/isisd/subdir.am
@@ -0,0 +1,71 @@
+#
+# isisd
+#
+
+if ISISD
+noinst_LIBRARIES += isisd/libisis.a
+sbin_PROGRAMS += isisd/isisd
+dist_examples_DATA += isisd/isisd.conf.sample
+endif
+
+isisd_libisis_a_SOURCES = \
+ isisd/dict.c \
+ isisd/isis_adjacency.c \
+ isisd/isis_circuit.c \
+ isisd/isis_csm.c \
+ isisd/isis_dr.c \
+ isisd/isis_dynhn.c \
+ isisd/isis_events.c \
+ isisd/isis_flags.c \
+ isisd/isis_lsp.c \
+ isisd/isis_memory.c \
+ isisd/isis_misc.c \
+ isisd/isis_mt.c \
+ isisd/isis_pdu.c \
+ isisd/isis_redist.c \
+ isisd/isis_route.c \
+ isisd/isis_routemap.c \
+ isisd/isis_spf.c \
+ isisd/isis_te.c \
+ isisd/isis_tlvs.c \
+ isisd/isis_vty.c \
+ isisd/isis_zebra.c \
+ isisd/isisd.c \
+ isisd/iso_checksum.c \
+ # end
+
+noinst_HEADERS += \
+ isisd/dict.h \
+ isisd/isis_adjacency.h \
+ isisd/isis_circuit.h \
+ isisd/isis_common.h \
+ isisd/isis_constants.h \
+ isisd/isis_csm.h \
+ isisd/isis_dr.h \
+ isisd/isis_dynhn.h \
+ isisd/isis_events.h \
+ isisd/isis_flags.h \
+ isisd/isis_lsp.h \
+ isisd/isis_memory.h \
+ isisd/isis_misc.h \
+ isisd/isis_mt.h \
+ isisd/isis_network.h \
+ isisd/isis_pdu.h \
+ isisd/isis_redist.h \
+ isisd/isis_route.h \
+ isisd/isis_routemap.h \
+ isisd/isis_spf.h \
+ isisd/isis_te.h \
+ isisd/isis_tlvs.h \
+ isisd/isis_zebra.h \
+ isisd/isisd.h \
+ isisd/iso_checksum.h \
+ # end
+
+isisd_isisd_LDADD = isisd/libisis.a lib/libfrr.la @LIBCAP@
+isisd_isisd_SOURCES = \
+ isisd/isis_bpf.c \
+ isisd/isis_dlpi.c \
+ isisd/isis_main.c \
+ isisd/isis_pfpacket.c \
+ # end
diff --git a/ldpd/.gitignore b/ldpd/.gitignore
index f52b227cb1..eee96c636f 100644
--- a/ldpd/.gitignore
+++ b/ldpd/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
ldpd
diff --git a/ldpd/Makefile b/ldpd/Makefile
new file mode 100644
index 0000000000..464e02cf51
--- /dev/null
+++ b/ldpd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. ldpd/ldpd
+%: ALWAYS
+ @$(MAKE) -s -C .. ldpd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am
deleted file mode 100644
index de9b07ed4c..0000000000
--- a/ldpd/Makefile.am
+++ /dev/null
@@ -1,30 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-include ../common.am
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(WERROR)
-
-noinst_LIBRARIES = libldp.a
-sbin_PROGRAMS = ldpd
-
-libldp_a_SOURCES = \
- accept.c address.c adjacency.c control.c hello.c init.c interface.c \
- keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \
- ldpe.c log.c logmsg.c neighbor.c notification.c packet.c pfkey.c \
- socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \
- ldp_debug.c ldp_zebra.c
-
-ldp_vty_cmds.o: ldp_vty_cmds_clippy.c
-
-noinst_HEADERS = \
- control.h lde.h ldpd.h ldpe.h ldp.h log.h ldp_debug.h ldp_vty.h
-
-ldpd_SOURCES = ldpd.c
-ldpd_LDADD = libldp.a ../lib/libfrr.la @LIBCAP@
-
-examplesdir = $(exampledir)
-dist_examples_DATA = ldpd.conf.sample
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 588ccd6952..4460b424d2 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -37,6 +37,7 @@
#include "zclient.h"
#include "stream.h"
#include "network.h"
+#include "libfrr.h"
static void lde_shutdown(void);
static int lde_dispatch_imsg(struct thread *);
@@ -164,13 +165,15 @@ lde_init(struct ldpd_init *init)
/* drop privileges */
lde_privs.user = init->user;
lde_privs.group = init->group;
+ zprivs_preinit(&lde_privs);
zprivs_init(&lde_privs);
/* start the LIB garbage collector */
lde_gc_start_timer();
/* Init synchronous zclient and label list */
- zclient_serv_path_set(init->zclient_serv_path);
+ frr_zclient_addr(&zclient_addr, &zclient_addr_len,
+ init->zclient_serv_path);
zclient_sync_init(init->instance);
lde_label_list_init();
}
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index 3f39ad926c..db92b93628 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -21,6 +21,8 @@
#include "command.h"
#include "vty.h"
+#include "json.h"
+
#include "ldpd/ldpd.h"
#include "ldpd/ldp_vty.h"
#include "ldpd/ldp_vty_cmds_clippy.c"
@@ -586,7 +588,7 @@ DEFPY (ldp_show_mpls_ldp_binding,
"IPv6 Address Family\n"
"Label Information Base (LIB) information\n"
"Show detailed information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_binding(vty, af, detail, json));
}
@@ -601,7 +603,7 @@ DEFPY (ldp_show_mpls_ldp_discovery,
"IPv6 Address Family\n"
"Discovery Hello Information\n"
"Show detailed information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_discovery(vty, af, detail, json));
}
@@ -615,7 +617,7 @@ DEFPY (ldp_show_mpls_ldp_interface,
"IPv4 Address Family\n"
"IPv6 Address Family\n"
"interface information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_interface(vty, af, json));
}
@@ -627,7 +629,7 @@ DEFPY (ldp_show_mpls_ldp_capabilities,
"MPLS information\n"
"Label Distribution Protocol\n"
"Display LDP Capabilities information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_capabilities(vty, json));
}
@@ -640,7 +642,7 @@ DEFPY (ldp_show_mpls_ldp_neighbor,
"Label Distribution Protocol\n"
"Neighbor information\n"
"Show detailed information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_neighbor(vty, 0, detail, json));
}
@@ -653,7 +655,7 @@ DEFPY (ldp_show_mpls_ldp_neighbor_capabilities,
"Label Distribution Protocol\n"
"Neighbor information\n"
"Display neighbor capability information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_neighbor(vty, 1, NULL, json));
}
@@ -665,7 +667,7 @@ DEFPY (ldp_show_l2vpn_atom_binding,
"Show information about Layer2 VPN\n"
"Show Any Transport over MPLS information\n"
"Show AToM label binding information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_atom_binding(vty, json));
}
@@ -677,7 +679,7 @@ DEFPY (ldp_show_l2vpn_atom_vc,
"Show information about Layer2 VPN\n"
"Show Any Transport over MPLS information\n"
"Show AToM virtual circuit information\n"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
return (ldp_vty_show_atom_vc(vty, json));
}
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 2d7afd5df8..80af2b14e5 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -256,7 +256,7 @@ main(int argc, char *argv[])
strlcpy(init.user, ldpd_privs.user, sizeof(init.user));
strlcpy(init.group, ldpd_privs.group, sizeof(init.group));
strlcpy(init.ctl_sock_path, ctl_sock_path, sizeof(init.ctl_sock_path));
- strlcpy(init.zclient_serv_path, zclient_serv_path_get(),
+ strlcpy(init.zclient_serv_path, frr_zclientpath,
sizeof(init.zclient_serv_path));
argc -= optind;
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index b2f9fdce55..1c0a8bdc84 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -142,6 +142,7 @@ ldpe_init(struct ldpd_init *init)
/* drop privileges */
ldpe_privs.user = init->user;
ldpe_privs.group = init->group;
+ zprivs_preinit(&ldpe_privs);
zprivs_init(&ldpe_privs);
/* listen on ldpd control socket */
diff --git a/ldpd/subdir.am b/ldpd/subdir.am
new file mode 100644
index 0000000000..db71cee618
--- /dev/null
+++ b/ldpd/subdir.am
@@ -0,0 +1,55 @@
+#
+# ldpd
+#
+
+if LDPD
+noinst_LIBRARIES += ldpd/libldp.a
+sbin_PROGRAMS += ldpd/ldpd
+dist_examples_DATA += ldpd/ldpd.conf.sample
+endif
+
+ldpd_libldp_a_SOURCES = \
+ ldpd/accept.c \
+ ldpd/address.c \
+ ldpd/adjacency.c \
+ ldpd/control.c \
+ ldpd/hello.c \
+ ldpd/init.c \
+ ldpd/interface.c \
+ ldpd/keepalive.c \
+ ldpd/l2vpn.c \
+ ldpd/labelmapping.c \
+ ldpd/lde.c \
+ ldpd/lde_lib.c \
+ ldpd/ldp_debug.c \
+ ldpd/ldp_vty_cmds.c \
+ ldpd/ldp_vty_conf.c \
+ ldpd/ldp_vty_exec.c \
+ ldpd/ldp_zebra.c \
+ ldpd/ldpd.c \
+ ldpd/ldpe.c \
+ ldpd/log.c \
+ ldpd/logmsg.c \
+ ldpd/neighbor.c \
+ ldpd/notification.c \
+ ldpd/packet.c \
+ ldpd/pfkey.c \
+ ldpd/socket.c \
+ ldpd/util.c \
+ # end
+
+ldpd/ldp_vty_cmds.$(OBJEXT): ldpd/ldp_vty_cmds_clippy.c
+
+noinst_HEADERS += \
+ ldpd/control.h \
+ ldpd/lde.h \
+ ldpd/ldp.h \
+ ldpd/ldp_debug.h \
+ ldpd/ldp_vty.h \
+ ldpd/ldpd.h \
+ ldpd/ldpe.h \
+ ldpd/log.h \
+ # end
+
+ldpd_ldpd_SOURCES = ldpd/ldpd.c
+ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la @LIBCAP@
diff --git a/lib/command.c b/lib/command.c
index 09ffa6ce56..077a72398d 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -101,6 +101,7 @@ const char *node_names[] = {
"ipv4 access list", // ACCESS_NODE,
"ipv4 prefix list", // PREFIX_NODE,
"ipv6 access list", // ACCESS_IPV6_NODE,
+ "MAC access list", // ACCESS_MAC_NODE,
"ipv6 prefix list", // PREFIX_IPV6_NODE,
"as list", // AS_LIST_NODE,
"community list", // COMMUNITY_LIST_NODE,
diff --git a/lib/command.h b/lib/command.h
index d0c9f0eaf9..8f12e2aabd 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -123,6 +123,7 @@ enum node_type {
ACCESS_NODE, /* Access list node. */
PREFIX_NODE, /* Prefix list node. */
ACCESS_IPV6_NODE, /* Access list node. */
+ ACCESS_MAC_NODE, /* MAC access list node*/
PREFIX_IPV6_NODE, /* Prefix list node. */
AS_LIST_NODE, /* AS list node. */
COMMUNITY_LIST_NODE, /* Community list node. */
diff --git a/lib/filter.c b/lib/filter.c
index 0262234c78..cb6f743c01 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -90,6 +90,14 @@ struct access_master {
void (*delete_hook)(struct access_list *);
};
+/* Static structure for mac access_list's master. */
+static struct access_master access_master_mac = {
+ {NULL, NULL},
+ {NULL, NULL},
+ NULL,
+ NULL,
+};
+
/* Static structure for IPv4 access_list's master. */
static struct access_master access_master_ipv4 = {
{NULL, NULL},
@@ -112,6 +120,8 @@ static struct access_master *access_master_get(afi_t afi)
return &access_master_ipv4;
else if (afi == AFI_IP6)
return &access_master_ipv6;
+ else if (afi == AFI_L2VPN)
+ return &access_master_mac;
return NULL;
}
@@ -173,7 +183,7 @@ static int filter_match_cisco(struct filter *mfilter, struct prefix *p)
/* If filter match to the prefix then return 1. */
static int filter_match_zebra(struct filter *mfilter, struct prefix *p)
{
- struct filter_zebra *filter;
+ struct filter_zebra *filter = NULL;
filter = &mfilter->u.zfilter;
@@ -365,9 +375,7 @@ static struct access_list *access_list_get(afi_t afi, const char *name)
enum filter_type access_list_apply(struct access_list *access, void *object)
{
struct filter *filter;
- struct prefix *p;
-
- p = (struct prefix *)object;
+ struct prefix *p = (struct prefix *)object;
if (access == NULL)
return FILTER_DENY;
@@ -390,6 +398,7 @@ void access_list_add_hook(void (*func)(struct access_list *access))
{
access_master_ipv4.add_hook = func;
access_master_ipv6.add_hook = func;
+ access_master_mac.add_hook = func;
}
/* Delete hook function. */
@@ -397,6 +406,7 @@ void access_list_delete_hook(void (*func)(struct access_list *access))
{
access_master_ipv4.delete_hook = func;
access_master_ipv6.delete_hook = func;
+ access_master_mac.delete_hook = func;
}
/* Add new filter to the end of specified access_list. */
@@ -515,10 +525,10 @@ static struct filter *filter_lookup_zebra(struct access_list *access,
filter = &mfilter->u.zfilter;
if (filter->exact == new->exact
- && mfilter->type
- == mnew->type &&prefix_same(&filter->prefix,
- &new->prefix))
- return mfilter;
+ && mfilter->type == mnew->type) {
+ if (prefix_same(&filter->prefix, &new->prefix))
+ return mfilter;
+ }
}
return NULL;
}
@@ -1252,6 +1262,12 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
"IPv6 address prefix/prefixlen is malformed\n");
return CMD_WARNING_CONFIG_FAILED;
}
+ } else if (afi == AFI_L2VPN) {
+ ret = str2prefix_eth(prefix_str, (struct prefix_eth *)&p);
+ if (ret <= 0) {
+ vty_out(vty, "MAC address is malformed\n");
+ return CMD_WARNING;
+ }
} else
return CMD_WARNING_CONFIG_FAILED;
@@ -1274,7 +1290,6 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
access_list_filter_add(access, mfilter);
} else {
struct filter *delete_filter;
-
delete_filter = filter_lookup_zebra(access, mfilter);
if (delete_filter)
access_list_filter_delete(access, delete_filter);
@@ -1285,6 +1300,64 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
return CMD_SUCCESS;
}
+DEFUN (mac_access_list,
+ mac_access_list_cmd,
+ "mac access-list WORD <deny|permit> MAC",
+ "Add a mac access-list\n"
+ "Add an access list entry\n"
+ "MAC zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "MAC address to match. e.g. 00:01:00:01:00:01\n")
+{
+ return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
+ argv[4]->arg, 0, 1);
+}
+
+DEFUN (no_mac_access_list,
+ no_mac_access_list_cmd,
+ "no mac access-list WORD <deny|permit> MAC",
+ NO_STR
+ "Remove a mac access-list\n"
+ "Remove an access list entry\n"
+ "MAC zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "MAC address to match. e.g. 00:01:00:01:00:01\n")
+{
+ return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
+ argv[5]->arg, 0, 0);
+}
+
+DEFUN (mac_access_list_any,
+ mac_access_list_any_cmd,
+ "mac access-list WORD <deny|permit> any",
+ "Add a mac access-list\n"
+ "Add an access list entry\n"
+ "MAC zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "MAC address to match. e.g. 00:01:00:01:00:01\n")
+{
+ return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
+ "00:00:00:00:00:00", 0, 1);
+}
+
+DEFUN (no_mac_access_list_any,
+ no_mac_access_list_any_cmd,
+ "no mac access-list WORD <deny|permit> any",
+ NO_STR
+ "Remove a mac access-list\n"
+ "Remove an access list entry\n"
+ "MAC zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "MAC address to match. e.g. 00:01:00:01:00:01\n")
+{
+ return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
+ "00:00:00:00:00:00", 0, 0);
+}
+
DEFUN (access_list_exact,
access_list_exact_cmd,
"access-list WORD <deny|permit> A.B.C.D/M [exact-match]",
@@ -1666,12 +1739,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
filter = &mfilter->u.cfilter;
if (write) {
- vty_out(vty, "%s IP%s access list %s\n",
+ vty_out(vty, "%s %s access list %s\n",
mfilter->cisco ? (filter->extended
? "Extended"
: "Standard")
: "Zebra",
- afi == AFI_IP6 ? "v6" : "",
+ (afi == AFI_IP)
+ ? ("IP")
+ : ((afi == AFI_IP6) ? ("IPv6 ")
+ : ("MAC ")),
access->name);
write = 0;
}
@@ -1710,12 +1786,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
filter = &mfilter->u.cfilter;
if (write) {
- vty_out(vty, "%s IP%s access list %s\n",
+ vty_out(vty, "%s %s access list %s\n",
mfilter->cisco ? (filter->extended
? "Extended"
: "Standard")
: "Zebra",
- afi == AFI_IP6 ? "v6" : "",
+ (afi == AFI_IP)
+ ? ("IP")
+ : ((afi == AFI_IP6) ? ("IPv6 ")
+ : ("MAC ")),
access->name);
write = 0;
}
@@ -1746,6 +1825,28 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
return CMD_SUCCESS;
}
+/* show MAC access list - this only has MAC filters for now*/
+DEFUN (show_mac_access_list,
+ show_mac_access_list_cmd,
+ "show mac access-list",
+ SHOW_STR
+ "mac access lists\n"
+ "List mac access lists\n")
+{
+ return filter_show(vty, NULL, AFI_L2VPN);
+}
+
+DEFUN (show_mac_access_list_name,
+ show_mac_access_list_name_cmd,
+ "show mac access-list WORD",
+ SHOW_STR
+ "mac access lists\n"
+ "List mac access lists\n"
+ "mac address\n")
+{
+ return filter_show(vty, argv[3]->arg, AFI_L2VPN);
+}
+
DEFUN (show_ip_access_list,
show_ip_access_list_cmd,
"show ip access-list",
@@ -1844,10 +1945,17 @@ void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
if (p->prefixlen == 0 && !filter->exact)
vty_out(vty, " any");
- else
+ else if (p->family == AF_INET6 || p->family == AF_INET)
vty_out(vty, " %s/%d%s",
inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen, filter->exact ? " exact-match" : "");
+ else if (p->family == AF_ETHERNET) {
+ if (p->prefixlen == 0)
+ vty_out(vty, " any");
+ else
+ vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth),
+ buf, sizeof(buf)));
+ }
vty_out(vty, "\n");
}
@@ -1866,15 +1974,19 @@ static int config_write_access(struct vty *vty, afi_t afi)
for (access = master->num.head; access; access = access->next) {
if (access->remark) {
vty_out(vty, "%saccess-list %s remark %s\n",
- afi == AFI_IP ? "" : "ipv6 ", access->name,
- access->remark);
+ (afi == AFI_IP) ? ("")
+ : ((afi == AFI_IP6) ? ("ipv6 ")
+ : ("mac ")),
+ access->name, access->remark);
write++;
}
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
vty_out(vty, "%saccess-list %s %s",
- afi == AFI_IP ? "" : "ipv6 ", access->name,
- filter_type_str(mfilter));
+ (afi == AFI_IP) ? ("")
+ : ((afi == AFI_IP6) ? ("ipv6 ")
+ : ("mac ")),
+ access->name, filter_type_str(mfilter));
if (mfilter->cisco)
config_write_access_cisco(vty, mfilter);
@@ -1888,15 +2000,19 @@ static int config_write_access(struct vty *vty, afi_t afi)
for (access = master->str.head; access; access = access->next) {
if (access->remark) {
vty_out(vty, "%saccess-list %s remark %s\n",
- afi == AFI_IP ? "" : "ipv6 ", access->name,
- access->remark);
+ (afi == AFI_IP) ? ("")
+ : ((afi == AFI_IP6) ? ("ipv6 ")
+ : ("mac ")),
+ access->name, access->remark);
write++;
}
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
vty_out(vty, "%saccess-list %s %s",
- afi == AFI_IP ? "" : "ipv6 ", access->name,
- filter_type_str(mfilter));
+ (afi == AFI_IP) ? ("")
+ : ((afi == AFI_IP6) ? ("ipv6 ")
+ : ("mac ")),
+ access->name, filter_type_str(mfilter));
if (mfilter->cisco)
config_write_access_cisco(vty, mfilter);
@@ -1909,6 +2025,56 @@ static int config_write_access(struct vty *vty, afi_t afi)
return write;
}
+static struct cmd_node access_mac_node = {
+ ACCESS_MAC_NODE, "", /* Access list has no interface. */
+ 1};
+
+static int config_write_access_mac(struct vty *vty)
+{
+ return config_write_access(vty, AFI_L2VPN);
+}
+
+static void access_list_reset_mac(void)
+{
+ struct access_list *access;
+ struct access_list *next;
+ struct access_master *master;
+
+ master = access_master_get(AFI_L2VPN);
+ if (master == NULL)
+ return;
+
+ for (access = master->num.head; access; access = next) {
+ next = access->next;
+ access_list_delete(access);
+ }
+ for (access = master->str.head; access; access = next) {
+ next = access->next;
+ access_list_delete(access);
+ }
+
+ assert(master->num.head == NULL);
+ assert(master->num.tail == NULL);
+
+ assert(master->str.head == NULL);
+ assert(master->str.tail == NULL);
+}
+
+/* Install vty related command. */
+static void access_list_init_mac(void)
+{
+ install_node(&access_mac_node, config_write_access_mac);
+
+ install_element(ENABLE_NODE, &show_mac_access_list_cmd);
+ install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
+
+ /* Zebra access-list */
+ install_element(CONFIG_NODE, &mac_access_list_cmd);
+ install_element(CONFIG_NODE, &no_mac_access_list_cmd);
+ install_element(CONFIG_NODE, &mac_access_list_any_cmd);
+ install_element(CONFIG_NODE, &no_mac_access_list_any_cmd);
+}
+
/* Access-list node. */
static struct cmd_node access_node = {ACCESS_NODE,
"", /* Access list has no interface. */
@@ -2050,10 +2216,12 @@ void access_list_init()
{
access_list_init_ipv4();
access_list_init_ipv6();
+ access_list_init_mac();
}
void access_list_reset()
{
access_list_reset_ipv4();
access_list_reset_ipv6();
+ access_list_reset_mac();
}
diff --git a/lib/gitversion.pl b/lib/gitversion.pl
index 8ddd9ffa55..2718046d0b 100644
--- a/lib/gitversion.pl
+++ b/lib/gitversion.pl
@@ -4,7 +4,7 @@ use strict;
my $dir = shift;
chdir $dir || die "$dir: $!\n";
-my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`;
+my $gitdesc = `git describe --always --first-parent --tags --dirty --match 'frr-*' || echo -- \"0-gUNKNOWN\"`;
chomp $gitdesc;
my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN";
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index c236d2c7be..89b0993d1d 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -26,10 +26,11 @@
#include "command.h"
#include "memory_vty.h"
-static void vty_do_exit(void)
+static void vty_do_exit(int isexit)
{
printf("\nend.\n");
- exit(0);
+ if (!isexit)
+ exit(0);
}
struct thread_master *master;
diff --git a/lib/hash.c b/lib/hash.c
index 801871f839..66341cf2f1 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -141,18 +141,15 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *))
unsigned int key;
unsigned int index;
void *newdata;
- unsigned int len;
struct hash_backet *backet;
key = (*hash->hash_key)(data);
index = key & (hash->size - 1);
- len = 0;
for (backet = hash->index[index]; backet != NULL;
backet = backet->next) {
if (backet->key == key && (*hash->hash_cmp)(backet->data, data))
return backet->data;
- ++len;
}
if (alloc_func) {
@@ -160,7 +157,7 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *))
if (newdata == NULL)
return NULL;
- if (len > HASH_THRESHOLD) {
+ if (HASH_THRESHOLD(hash->count + 1, hash->size)) {
hash_expand(hash);
index = key & (hash->size - 1);
}
diff --git a/lib/hash.h b/lib/hash.h
index 236abbbd6a..b6fe27e257 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -28,8 +28,9 @@ DECLARE_MTYPE(HASH)
DECLARE_MTYPE(HASH_BACKET)
/* Default hash table size. */
-#define HASH_INITIAL_SIZE 256 /* initial number of backets. */
-#define HASH_THRESHOLD 10 /* expand when backet. */
+#define HASH_INITIAL_SIZE 256
+/* Expansion threshold */
+#define HASH_THRESHOLD(used, size) ((used) > (size))
#define HASHWALK_CONTINUE 0
#define HASHWALK_ABORT -1
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 022296b3fb..e5573da900 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -19,9 +19,14 @@
*/
#include <zebra.h>
+#include <sys/un.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
#include "libfrr.h"
#include "getopt.h"
+#include "privs.h"
#include "vty.h"
#include "command.h"
#include "version.h"
@@ -29,6 +34,7 @@
#include "zclient.h"
#include "log_int.h"
#include "module.h"
+#include "network.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
@@ -40,6 +46,7 @@ char frr_protoname[256] = "NONE";
char frr_protonameinst[256] = "NONE";
char config_default[256];
+char frr_zclientpath[256];
static char pidfile_default[256];
static char vtypath_default[256];
@@ -91,12 +98,15 @@ static const struct option lo_cfg_pid_dry[] = {
{"pid_file", required_argument, NULL, 'i'},
{"config_file", required_argument, NULL, 'f'},
{"dryrun", no_argument, NULL, 'C'},
+ {"terminal", no_argument, NULL, 't'},
{NULL}};
static const struct optspec os_cfg_pid_dry = {
- "f:i:C",
+ "f:i:Ct",
" -f, --config_file Set configuration file name\n"
" -i, --pid_file Set process identifier file name\n"
- " -C, --dryrun Check configuration for validity and exit\n",
+ " -C, --dryrun Check configuration for validity and exit\n"
+ " -t, --terminal Open terminal session on stdio\n"
+ " -d -t Daemonize after terminal session ends\n",
lo_cfg_pid_dry};
@@ -127,6 +137,116 @@ static const struct optspec os_user = {"u:g:",
lo_user};
+bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
+ const char *path)
+{
+ memset(sa, 0, sizeof(*sa));
+
+ if (!path)
+ path = ZEBRA_SERV_PATH;
+
+ if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) {
+ /* note: this functionality is disabled at bottom */
+ int af;
+ int port = ZEBRA_PORT;
+ char *err = NULL;
+ struct sockaddr_in *sin = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
+
+ path += strlen(ZAPI_TCP_PATHNAME);
+
+ switch (path[0]) {
+ case '4':
+ path++;
+ af = AF_INET;
+ break;
+ case '6':
+ path++;
+ /* fallthrough */
+ default:
+ af = AF_INET6;
+ break;
+ }
+
+ switch (path[0]) {
+ case '\0':
+ break;
+ case ':':
+ path++;
+ port = strtoul(path, &err, 10);
+ if (*err || !*path)
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ sa->ss_family = af;
+ switch (af) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)sa;
+ sin->sin_port = htons(port);
+ sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ *sa_len = sizeof(struct sockaddr_in);
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin->sin_len = *sa_len;
+#endif
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_port = htons(port);
+ inet_pton(AF_INET6, "::1", &sin6->sin6_addr);
+ *sa_len = sizeof(struct sockaddr_in6);
+#ifdef SIN6_LEN
+ sin6->sin6_len = *sa_len;
+#endif
+ break;
+ }
+
+#if 1
+ /* force-disable this path, because tcp-zebra is a
+ * SECURITY ISSUE. there are no checks at all against
+ * untrusted users on the local system connecting on TCP
+ * and injecting bogus routing data into the entire routing
+ * domain.
+ *
+ * The functionality is only left here because it may be
+ * useful during development, in order to be able to get
+ * tcpdump or wireshark watching ZAPI as TCP. If you want
+ * to do that, flip the #if 1 above to #if 0. */
+ memset(sa, 0, sizeof(*sa));
+ return false;
+#endif
+ } else {
+ /* "sun" is a #define on solaris */
+ struct sockaddr_un *suna = (struct sockaddr_un *)sa;
+
+ suna->sun_family = AF_UNIX;
+ strlcpy(suna->sun_path, path, sizeof(suna->sun_path));
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ *sa_len = suna->sun_len = SUN_LEN(suna);
+#else
+ *sa_len = sizeof(suna->sun_family) + strlen(suna->sun_path);
+#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
+#if 0
+ /* this is left here for future reference; Linux abstract
+ * socket namespace support can be enabled by replacing
+ * above #if 0 with #ifdef GNU_LINUX.
+ *
+ * THIS IS A SECURITY ISSUE, the abstract socket namespace
+ * does not have user/group permission control on sockets.
+ * we'd need to implement SCM_CREDENTIALS support first to
+ * check that only proper users can connect to abstract
+ * sockets. (same problem as tcp-zebra, except there is a
+ * fix with SCM_CREDENTIALS. tcp-zebra has no such fix.)
+ */
+ if (suna->sun_path[0] == '@')
+ suna->sun_path[0] = '\0';
+#endif
+ }
+ return true;
+}
+
static struct frr_daemon_info *di = NULL;
void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
@@ -156,6 +276,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
strlcpy(frr_protoname, di->logname, sizeof(frr_protoname));
strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst));
+
+ strlcpy(frr_zclientpath, ZEBRA_SERV_PATH, sizeof(frr_zclientpath));
}
void frr_opt_add(const char *optstr, const struct option *longopts,
@@ -230,10 +352,15 @@ static int frr_opt(int opt)
return 1;
di->dryrun = 1;
break;
+ case 't':
+ if (di->flags & FRR_NO_CFG_PID_DRY)
+ return 1;
+ di->terminal = 1;
+ break;
case 'z':
if (di->flags & FRR_NO_ZCLIENT)
return 1;
- zclient_serv_path_set(optarg);
+ strlcpy(frr_zclientpath, optarg, sizeof(frr_zclientpath));
break;
case 'A':
if (di->flags & FRR_NO_TCPVTY)
@@ -320,6 +447,49 @@ int frr_getopt(int argc, char *const argv[], int *longindex)
return opt;
}
+static void frr_mkdir(const char *path, bool strip)
+{
+ char buf[256];
+ mode_t prev;
+ int ret;
+ struct zprivs_ids_t ids;
+
+ if (strip) {
+ char *slash = strrchr(path, '/');
+ size_t plen;
+ if (!slash)
+ return;
+ plen = slash - path;
+ if (plen > sizeof(buf) - 1)
+ return;
+ memcpy(buf, path, plen);
+ buf[plen] = '\0';
+ path = buf;
+ }
+
+ /* o+rx (..5) is needed for the frrvty group to work properly;
+ * without it, users in the frrvty group can't access the vty sockets.
+ */
+ prev = umask(0022);
+ ret = mkdir(path, 0755);
+ umask(prev);
+
+ if (ret != 0) {
+ /* if EEXIST, return without touching the permissions,
+ * so user-set custom permissions are left in place
+ */
+ if (errno == EEXIST)
+ return;
+
+ zlog_warn("failed to mkdir \"%s\": %s", path, strerror(errno));
+ return;
+ }
+
+ zprivs_get_ids(&ids);
+ if (chown(path, ids.uid_normal, ids.gid_normal))
+ zlog_warn("failed to chown \"%s\": %s", path, strerror(errno));
+}
+
static struct thread_master *master;
struct thread_master *frr_init(void)
{
@@ -335,12 +505,31 @@ struct thread_master *frr_init(void)
snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]",
di->logname, di->instance);
+ zprivs_preinit(di->privs);
+
openzlog(di->progname, di->logname, di->instance,
LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
#if defined(HAVE_CUMULUS)
zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
#endif
+ if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
+ frr_zclientpath)) {
+ fprintf(stderr, "Invalid zserv socket path: %s\n",
+ frr_zclientpath);
+ exit(1);
+ }
+
+ /* don't mkdir these as root... */
+ if (!(di->flags & FRR_NO_PRIVSEP)) {
+ if (!di->pid_file || !di->vty_path)
+ frr_mkdir(frr_vtydir, false);
+ if (di->pid_file)
+ frr_mkdir(di->pid_file, true);
+ if (di->vty_path)
+ frr_mkdir(di->vty_path, true);
+ }
+
frrmod_init(di->module);
while (modules) {
modules = (oc = modules)->next;
@@ -367,6 +556,134 @@ struct thread_master *frr_init(void)
return master;
}
+static int rcvd_signal = 0;
+
+static void rcv_signal(int signum)
+{
+ rcvd_signal = signum;
+ /* poll() is interrupted by the signal; handled below */
+}
+
+static void frr_daemon_wait(int fd)
+{
+ struct pollfd pfd[1];
+ int ret;
+ pid_t exitpid;
+ int exitstat;
+ sigset_t sigs, prevsigs;
+
+ sigemptyset(&sigs);
+ sigaddset(&sigs, SIGTSTP);
+ sigaddset(&sigs, SIGQUIT);
+ sigaddset(&sigs, SIGINT);
+ sigprocmask(SIG_BLOCK, &sigs, &prevsigs);
+
+ struct sigaction sa = {
+ .sa_handler = rcv_signal, .sa_flags = SA_RESETHAND,
+ };
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGTSTP, &sa, NULL);
+ sigaction(SIGQUIT, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ do {
+ char buf[1];
+ ssize_t nrecv;
+
+ pfd[0].fd = fd;
+ pfd[0].events = POLLIN;
+
+ rcvd_signal = 0;
+
+#if defined(HAVE_PPOLL)
+ ret = ppoll(pfd, 1, NULL, &prevsigs);
+#elif defined(HAVE_POLLTS)
+ ret = pollts(pfd, 1, NULL, &prevsigs);
+#else
+ /* racy -- only used on FreeBSD 9 */
+ sigset_t tmpsigs;
+ sigprocmask(SIG_SETMASK, &prevsigs, &tmpsigs);
+ ret = poll(pfd, 1, -1);
+ sigprocmask(SIG_SETMASK, &tmpsigs, NULL);
+#endif
+ if (ret < 0 && errno != EINTR && errno != EAGAIN) {
+ perror("poll()");
+ exit(1);
+ }
+ switch (rcvd_signal) {
+ case SIGTSTP:
+ send(fd, "S", 1, 0);
+ do {
+ nrecv = recv(fd, buf, sizeof(buf), 0);
+ } while (nrecv == -1
+ && (errno == EINTR || errno == EAGAIN));
+
+ raise(SIGTSTP);
+ sigaction(SIGTSTP, &sa, NULL);
+ send(fd, "R", 1, 0);
+ break;
+ case SIGINT:
+ send(fd, "I", 1, 0);
+ break;
+ case SIGQUIT:
+ send(fd, "Q", 1, 0);
+ break;
+ }
+ } while (ret <= 0);
+
+ exitpid = waitpid(-1, &exitstat, WNOHANG);
+ if (exitpid == 0)
+ /* child successfully went to main loop & closed socket */
+ exit(0);
+
+ /* child failed one way or another ... */
+ if (WIFEXITED(exitstat))
+ fprintf(stderr, "%s failed to start, exited %d\n", di->name,
+ WEXITSTATUS(exitstat));
+ else if (WIFSIGNALED(exitstat))
+ fprintf(stderr, "%s crashed in startup, signal %d\n", di->name,
+ WTERMSIG(exitstat));
+ else
+ fprintf(stderr, "%s failed to start, unknown problem\n",
+ di->name);
+ exit(1);
+}
+
+static int daemon_ctl_sock = -1;
+
+static void frr_daemonize(void)
+{
+ int fds[2];
+ pid_t pid;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
+ perror("socketpair() for daemon control");
+ exit(1);
+ }
+ set_cloexec(fds[0]);
+ set_cloexec(fds[1]);
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork()");
+ exit(1);
+ }
+ if (pid == 0) {
+ /* child */
+ close(fds[0]);
+ if (setsid() < 0) {
+ perror("setsid()");
+ exit(1);
+ }
+
+ daemon_ctl_sock = fds[1];
+ return;
+ }
+
+ close(fds[1]);
+ frr_daemon_wait(fds[0]);
+}
+
void frr_config_fork(void)
{
hook_call(frr_late_init, master);
@@ -385,11 +702,8 @@ void frr_config_fork(void)
if (di->dryrun)
exit(0);
- /* Daemonize. */
- if (di->daemon_mode && daemon(0, 0) < 0) {
- zlog_err("Zebra daemon failed: %s", strerror(errno));
- exit(1);
- }
+ if (di->daemon_mode || di->terminal)
+ frr_daemonize();
if (!di->pid_file)
di->pid_file = pidfile_default;
@@ -417,6 +731,67 @@ void frr_vty_serv(void)
vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path);
}
+static void frr_terminal_close(int isexit)
+{
+ if (daemon_ctl_sock != -1) {
+ close(daemon_ctl_sock);
+ daemon_ctl_sock = -1;
+ }
+
+ if (!di->daemon_mode || isexit) {
+ printf("\n%s exiting\n", di->name);
+ if (!isexit)
+ raise(SIGINT);
+ return;
+ } else {
+ printf("\n%s daemonizing\n", di->name);
+ fflush(stdout);
+ }
+
+ int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
+ dup2(nullfd, 0);
+ dup2(nullfd, 1);
+ dup2(nullfd, 2);
+ close(nullfd);
+}
+
+static struct thread *daemon_ctl_thread = NULL;
+
+static int frr_daemon_ctl(struct thread *t)
+{
+ char buf[1];
+ ssize_t nr;
+
+ nr = recv(daemon_ctl_sock, buf, sizeof(buf), 0);
+ if (nr < 0 && (errno == EINTR || errno == EAGAIN))
+ goto out;
+ if (nr <= 0)
+ return 0;
+
+ switch (buf[0]) {
+ case 'S': /* SIGTSTP */
+ vty_stdio_suspend();
+ send(daemon_ctl_sock, "s", 1, 0);
+ break;
+ case 'R': /* SIGTCNT [implicit] */
+ vty_stdio_resume();
+ break;
+ case 'I': /* SIGINT */
+ di->daemon_mode = false;
+ raise(SIGINT);
+ break;
+ case 'Q': /* SIGQUIT */
+ di->daemon_mode = true;
+ vty_stdio_close();
+ break;
+ }
+
+out:
+ thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock,
+ &daemon_ctl_thread);
+ return 0;
+}
+
void frr_run(struct thread_master *master)
{
char instanceinfo[64] = "";
@@ -430,6 +805,28 @@ void frr_run(struct thread_master *master)
zlog_notice("%s %s starting: %svty@%d%s", di->name, FRR_VERSION,
instanceinfo, di->vty_port, di->startinfo);
+ if (di->terminal) {
+ vty_stdio(frr_terminal_close);
+ if (daemon_ctl_sock != -1) {
+ set_nonblocking(daemon_ctl_sock);
+ thread_add_read(master, frr_daemon_ctl, NULL,
+ daemon_ctl_sock, &daemon_ctl_thread);
+ }
+ } else {
+ int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
+ dup2(nullfd, 0);
+ dup2(nullfd, 1);
+ dup2(nullfd, 2);
+ close(nullfd);
+
+ if (daemon_ctl_sock != -1)
+ close(daemon_ctl_sock);
+ daemon_ctl_sock = -1;
+ }
+
+ /* end fixed stderr startup logging */
+ zlog_startup_stderr = false;
+
struct thread thread;
while (thread_fetch(master, &thread))
thread_call(&thread);
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 0f6ed0cb00..1710fc9a84 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -49,6 +49,7 @@ struct frr_daemon_info {
char *vty_sock_path;
bool dryrun;
bool daemon_mode;
+ bool terminal;
const char *config_file;
const char *pid_file;
const char *vty_path;
@@ -100,7 +101,11 @@ extern void frr_vty_serv(void);
/* note: contains call to frr_vty_serv() */
extern void frr_run(struct thread_master *master);
+extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
+ const char *path);
+
extern char config_default[256];
+extern char frr_zclientpath[256];
extern const char frr_sysconfdir[];
extern const char frr_vtydir[];
extern const char frr_moduledir[];
diff --git a/lib/log.c b/lib/log.c
index 63afbf5137..5c89e7080e 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -41,6 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging")
static int logfile_fd = -1; /* Used in signal handler. */
struct zlog *zlog_default = NULL;
+bool zlog_startup_stderr = true;
const char *zlog_priority[] = {
"emergencies", "alerts", "critical", "errors", "warnings",
@@ -172,6 +173,25 @@ static void time_print(FILE *fp, struct timestamp_control *ctl)
}
+static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl,
+ const char *proto_str, int record_priority,
+ int priority, FILE *fp, const char *format,
+ va_list args)
+{
+ va_list ac;
+
+ time_print(fp, tsctl);
+ if (record_priority)
+ fprintf(fp, "%s: ", zlog_priority[priority]);
+
+ fprintf(fp, "%s", proto_str);
+ va_copy(ac, args);
+ vfprintf(fp, format, ac);
+ va_end(ac);
+ fprintf(fp, "\n");
+ fflush(fp);
+}
+
/* va_list version of zlog. */
void vzlog(int priority, const char *format, va_list args)
{
@@ -210,32 +230,21 @@ void vzlog(int priority, const char *format, va_list args)
sprintf(proto_str, "%s: ", zl->protoname);
/* File output. */
- if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) {
- va_list ac;
- time_print(zl->fp, &tsctl);
- if (zl->record_priority)
- fprintf(zl->fp, "%s: ", zlog_priority[priority]);
- fprintf(zl->fp, "%s", proto_str);
- va_copy(ac, args);
- vfprintf(zl->fp, format, ac);
- va_end(ac);
- fprintf(zl->fp, "\n");
- fflush(zl->fp);
- }
-
- /* stdout output. */
- if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) {
- va_list ac;
- time_print(stdout, &tsctl);
- if (zl->record_priority)
- fprintf(stdout, "%s: ", zlog_priority[priority]);
- fprintf(stdout, "%s", proto_str);
- va_copy(ac, args);
- vfprintf(stdout, format, ac);
- va_end(ac);
- fprintf(stdout, "\n");
- fflush(stdout);
- }
+ if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
+ vzlog_file(zl, &tsctl, proto_str, zl->record_priority,
+ priority, zl->fp, format, args);
+
+ /* fixed-config logging to stderr while we're stating up & haven't
+ * daemonized / reached mainloop yet
+ *
+ * note the "else" on stdout output -- we don't want to print the same
+ * message to both stderr and stdout. */
+ if (zlog_startup_stderr && priority <= LOG_WARNING)
+ vzlog_file(zl, &tsctl, proto_str, 1,
+ priority, stderr, format, args);
+ else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
+ vzlog_file(zl, &tsctl, proto_str, zl->record_priority,
+ priority, stdout, format, args);
/* Terminal monitor. */
if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
@@ -908,6 +917,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
+ DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_VNI_ADD),
DESC_ENTRY(ZEBRA_VNI_DEL),
DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD),
diff --git a/lib/log.h b/lib/log.h
index d872ce56d6..07eb6d5bd5 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -24,6 +24,7 @@
#include <syslog.h>
#include <stdint.h>
+#include <stdbool.h>
#include <stdio.h>
/* Here is some guidance on logging levels to use:
@@ -54,6 +55,8 @@ typedef enum {
} zlog_dest_t;
#define ZLOG_NUM_DESTS (ZLOG_DEST_FILE+1)
+extern bool zlog_startup_stderr;
+
/* Message structure. */
struct message {
int key;
diff --git a/lib/prefix.c b/lib/prefix.c
index 33b6ff1987..de521b2e3e 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -37,390 +37,262 @@ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
static const struct in6_addr maskbytes6[] = {
/* /0 */ {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /1 */
- {{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /2 */
- {{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /3 */
- {{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /4 */
- {{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /5 */
- {{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /6 */
- {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /7 */
- {{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /8 */
- {{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /9 */
- {{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /10 */
- {{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /11 */
- {{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /12 */
- {{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /13 */
- {{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /14 */
- {{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /15 */
- {{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /16 */
- {{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /17 */
- {{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /18 */
- {{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /19 */
- {{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /20 */
- {{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /21 */
- {{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /22 */
- {{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /23 */
- {{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /24 */
- {{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /25 */
- {{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /26 */
- {{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /27 */
- {{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /28 */
- {{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /29 */
- {{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /30 */
- {{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /31 */
- {{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /32 */
- {{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /33 */
- {{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /34 */
- {{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /35 */
- {{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /36 */
- {{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /37 */
- {{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /38 */
- {{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /39 */
- {{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /40 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /41 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /42 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /43 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /44 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /45 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /46 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /47 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /48 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /49 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /50 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /51 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /52 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /53 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /54 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /55 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /56 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /57 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /58 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /59 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /60 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /61 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /62 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /63 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /64 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /65 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /66 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /67 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /68 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /69 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /70 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /71 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /72 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /73 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /74 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /75 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /76 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /77 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /78 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /79 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /80 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /81 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /82 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /83 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /84 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /85 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /86 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /87 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /88 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /89 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x80, 0x00, 0x00, 0x00, 0x00}}},
- /* /90 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xc0, 0x00, 0x00, 0x00, 0x00}}},
- /* /91 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xe0, 0x00, 0x00, 0x00, 0x00}}},
- /* /92 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xf0, 0x00, 0x00, 0x00, 0x00}}},
- /* /93 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xf8, 0x00, 0x00, 0x00, 0x00}}},
- /* /94 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfc, 0x00, 0x00, 0x00, 0x00}}},
- /* /95 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfe, 0x00, 0x00, 0x00, 0x00}}},
- /* /96 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00}}},
- /* /97 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x80, 0x00, 0x00, 0x00}}},
- /* /98 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xc0, 0x00, 0x00, 0x00}}},
- /* /99 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xe0, 0x00, 0x00, 0x00}}},
- /* /100 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xf0, 0x00, 0x00, 0x00}}},
- /* /101 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xf8, 0x00, 0x00, 0x00}}},
- /* /102 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xfc, 0x00, 0x00, 0x00}}},
- /* /103 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xfe, 0x00, 0x00, 0x00}}},
- /* /104 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00}}},
- /* /105 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x80, 0x00, 0x00}}},
- /* /106 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xc0, 0x00, 0x00}}},
- /* /107 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xe0, 0x00, 0x00}}},
- /* /108 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xf0, 0x00, 0x00}}},
- /* /109 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xf8, 0x00, 0x00}}},
- /* /110 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xfc, 0x00, 0x00}}},
- /* /111 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xfe, 0x00, 0x00}}},
- /* /112 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x00, 0x00}}},
- /* /113 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x80, 0x00}}},
- /* /114 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xc0, 0x00}}},
- /* /115 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xe0, 0x00}}},
- /* /116 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xf0, 0x00}}},
- /* /117 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xf8, 0x00}}},
- /* /118 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xfc, 0x00}}},
- /* /119 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xfe, 0x00}}},
- /* /120 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00}}},
- /* /121 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x80}}},
- /* /122 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xc0}}},
- /* /123 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xe0}}},
- /* /124 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xf0}}},
- /* /125 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xf8}}},
- /* /126 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xfc}}},
- /* /127 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xfe}}},
- /* /128 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff}}}};
+ /* /1 */ {{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /2 */ {{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /3 */ {{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /4 */ {{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /5 */ {{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /6 */ {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /7 */ {{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /8 */ {{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /9 */ {{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /10 */ {{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /11 */ {{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /12 */ {{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /13 */ {{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /14 */ {{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /15 */ {{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /16 */ {{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /17 */ {{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /18 */ {{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /19 */ {{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /20 */ {{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /21 */ {{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /22 */ {{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /23 */ {{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /24 */ {{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /25 */ {{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /26 */ {{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /27 */ {{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /28 */ {{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /29 */ {{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /30 */ {{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /31 */ {{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /32 */ {{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /33 */ {{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /34 */ {{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /35 */ {{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /36 */ {{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /37 */ {{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /38 */ {{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /39 */ {{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /40 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /41 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /42 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /43 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /44 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /45 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /46 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /47 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /48 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /49 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /50 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /51 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /52 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /53 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /54 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /55 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /56 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /57 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /58 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /59 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /60 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /61 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /62 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /63 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /64 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /65 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /66 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /67 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /68 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /69 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /70 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /71 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /72 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /73 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /74 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /75 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /76 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /77 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /78 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /79 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /80 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /81 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /82 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /83 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /84 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /85 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /86 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /87 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /88 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+ /* /89 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00}}},
+ /* /90 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00}}},
+ /* /91 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00}}},
+ /* /92 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00}}},
+ /* /93 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00}}},
+ /* /94 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00}}},
+ /* /95 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00}}},
+ /* /96 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}}},
+ /* /97 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00}}},
+ /* /98 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00}}},
+ /* /99 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00}}},
+ /* /100 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00}}},
+ /* /101 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00}}},
+ /* /102 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00}}},
+ /* /103 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00}}},
+ /* /104 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}},
+ /* /105 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00}}},
+ /* /106 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00}}},
+ /* /107 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00}}},
+ /* /108 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00}}},
+ /* /109 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00}}},
+ /* /110 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00}}},
+ /* /111 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00}}},
+ /* /112 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00}}},
+ /* /113 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00}}},
+ /* /114 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00}}},
+ /* /115 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00}}},
+ /* /116 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00}}},
+ /* /117 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00}}},
+ /* /118 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00}}},
+ /* /119 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00}}},
+ /* /120 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}},
+ /* /121 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80}}},
+ /* /122 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0}}},
+ /* /123 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0}}},
+ /* /124 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}}},
+ /* /125 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8}}},
+ /* /126 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}}},
+ /* /127 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}},
+ /* /128 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}};
/* Number of bits in prefix type. */
#ifndef PNBBY
@@ -429,6 +301,18 @@ static const struct in6_addr maskbytes6[] = {
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
+static int is_zero_mac(const struct ethaddr *mac)
+{
+ int i = 0;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if (mac->octet[i])
+ return 0;
+ }
+
+ return 1;
+}
+
unsigned int prefix_bit(const u_char *prefix, const u_char prefixlen)
{
unsigned int offset = prefixlen / 8;
@@ -450,6 +334,8 @@ int str2family(const char *string)
return AF_INET6;
else if (!strcmp("ethernet", string))
return AF_ETHERNET;
+ else if (!strcmp("evpn", string))
+ return AF_EVPN;
return -1;
}
@@ -462,6 +348,7 @@ int afi2family(afi_t afi)
return AF_INET6;
else if (afi == AFI_L2VPN)
return AF_ETHERNET;
+ /* NOTE: EVPN code should NOT use this interface. */
return 0;
}
@@ -471,7 +358,7 @@ afi_t family2afi(int family)
return AFI_IP;
else if (family == AF_INET6)
return AFI_IP6;
- else if (family == AF_ETHERNET)
+ else if (family == AF_ETHERNET || family == AF_EVPN)
return AFI_L2VPN;
return 0;
}
@@ -577,6 +464,9 @@ void prefix_copy(struct prefix *dest, const struct prefix *src)
else if (src->family == AF_INET6)
dest->u.prefix6 = src->u.prefix6;
else if (src->family == AF_ETHERNET) {
+ memcpy(&dest->u.prefix_eth, &src->u.prefix_eth,
+ sizeof(struct ethaddr));
+ } else if (src->family == AF_EVPN) {
memcpy(&dest->u.prefix_evpn, &src->u.prefix_evpn,
sizeof(struct evpn_addr));
} else if (src->family == AF_UNSPEC) {
@@ -615,6 +505,10 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2)
&p2->u.prefix6.s6_addr))
return 1;
if (p1->family == AF_ETHERNET)
+ if (!memcmp(&p1->u.prefix_eth, &p2->u.prefix_eth,
+ sizeof(struct ethaddr)))
+ return 1;
+ if (p1->family == AF_EVPN)
if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn,
sizeof(struct evpn_addr)))
return 1;
@@ -679,6 +573,8 @@ int prefix_common_bits(const struct prefix *p1, const struct prefix *p2)
if (p1->family == AF_INET6)
length = IPV6_MAX_BYTELEN;
if (p1->family == AF_ETHERNET)
+ length = ETH_ALEN;
+ if (p1->family == AF_EVPN)
length = 8 * sizeof(struct evpn_addr);
if (p1->family != p2->family || !length)
@@ -707,6 +603,8 @@ const char *prefix_family_str(const struct prefix *p)
return "inet6";
if (p->family == AF_ETHERNET)
return "ether";
+ if (p->family == AF_EVPN)
+ return "evpn";
return "unspec";
}
@@ -783,6 +681,13 @@ int str2prefix_eth(const char *str, struct prefix_eth *p)
const char *str_addr = str;
unsigned int a[6];
int i;
+ bool slash = false;
+
+ if (!strcmp(str, "any")) {
+ memset(p, 0, sizeof(*p));
+ p->family = AF_ETHERNET;
+ return 1;
+ }
/* Find slash inside string. */
pnt = strchr(str, '/');
@@ -800,6 +705,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p)
*(cp + (pnt - str)) = '\0';
str_addr = cp;
+ slash = true;
}
/* Convert string to prefix. */
@@ -814,6 +720,15 @@ int str2prefix_eth(const char *str, struct prefix_eth *p)
}
p->prefixlen = plen;
p->family = AF_ETHERNET;
+
+ /*
+ * special case to allow old configurations to work
+ * Since all zero's is implicitly meant to allow
+ * a comparison to zero, let's assume
+ */
+ if (!slash && is_zero_mac(&(p->eth_addr)))
+ p->prefixlen = 0;
+
ret = 1;
done:
@@ -1063,6 +978,7 @@ int prefix_blen(const struct prefix *p)
break;
case AF_ETHERNET:
return ETH_ALEN;
+ break;
}
return 0;
}
@@ -1090,7 +1006,7 @@ int str2prefix(const char *str, struct prefix *p)
return 0;
}
-static const char *prefixeth2str(const struct prefix *p, char *str, int size)
+static const char *prefixevpn2str(const struct prefix *p, char *str, int size)
{
u_char family;
char buf[PREFIX2STR_BUFFER];
@@ -1134,12 +1050,8 @@ static const char *prefixeth2str(const struct prefix *p, char *str, int size)
PREFIX2STR_BUFFER),
p->prefixlen);
} else {
- sprintf(str, "UNK AF_ETHER prefix");
- snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d",
- p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1],
- p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3],
- p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5],
- p->prefixlen);
+ sprintf(str, "Unsupported EVPN route type %d",
+ p->u.prefix_evpn.route_type);
}
return str;
@@ -1159,7 +1071,13 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
break;
case AF_ETHERNET:
- prefixeth2str(p, str, size);
+ snprintf(str, size, "%s/%d",
+ prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)),
+ p->prefixlen);
+ break;
+
+ case AF_EVPN:
+ prefixevpn2str(p, str, size);
break;
default:
diff --git a/lib/prefix.h b/lib/prefix.h
index 5f2b57ccce..f0644ea88e 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -116,7 +116,18 @@ struct evpn_addr {
#endif
#endif
-/* IPv4 and IPv6 unified prefix structure. */
+/* The 'family' in the prefix structure is internal to FRR and need not
+ * map to standard OS AF_ definitions except where needed for interacting
+ * with the kernel. However, AF_ definitions are currently in use and
+ * prevalent across the code. Define a new FRR-specific AF for EVPN to
+ * distinguish between 'ethernet' (MAC-only) and 'evpn' prefixes and
+ * ensure it does not conflict with any OS AF_ definition.
+ */
+#if !defined(AF_EVPN)
+#define AF_EVPN (AF_MAX + 1)
+#endif
+
+/* FRR generic prefix structure. */
struct prefix {
u_char family;
u_char prefixlen;
@@ -131,7 +142,7 @@ struct prefix {
struct ethaddr prefix_eth; /* AF_ETHERNET */
u_char val[8];
uintptr_t ptr;
- struct evpn_addr prefix_evpn;
+ struct evpn_addr prefix_evpn; /* AF_EVPN */
} u __attribute__((aligned(8)));
};
@@ -356,6 +367,7 @@ static inline int ipv6_martian(struct in6_addr *addr)
}
extern int all_digit(const char *);
+extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
/* NOTE: This routine expects the address argument in network byte order. */
static inline int ipv4_martian(struct in_addr *addr)
diff --git a/lib/privs.c b/lib/privs.c
index c971596117..eda3fb02d4 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -696,13 +696,10 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups,
}
#endif /* HAVE_GETGROUPLIST */
-void zprivs_init(struct zebra_privs_t *zprivs)
+void zprivs_preinit(struct zebra_privs_t *zprivs)
{
struct passwd *pwentry = NULL;
struct group *grentry = NULL;
- gid_t groups[NGROUPS_MAX];
- int i, ngroups = 0;
- int found = 0;
if (!zprivs) {
fprintf(stderr, "zprivs_init: called with NULL arg!\n");
@@ -751,6 +748,18 @@ void zprivs_init(struct zebra_privs_t *zprivs)
zprivs_state.zgid = grentry->gr_gid;
}
+}
+
+void zprivs_init(struct zebra_privs_t *zprivs)
+{
+ gid_t groups[NGROUPS_MAX];
+ int i, ngroups = 0;
+ int found = 0;
+
+ /* NULL privs */
+ if (!(zprivs->user || zprivs->group || zprivs->cap_num_p
+ || zprivs->cap_num_i))
+ return;
if (zprivs->user) {
ngroups = sizeof(groups);
diff --git a/lib/privs.h b/lib/privs.h
index c18fe78add..7fe59328b2 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -74,6 +74,7 @@ struct zprivs_ids_t {
};
/* initialise zebra privileges */
+extern void zprivs_preinit(struct zebra_privs_t *zprivs);
extern void zprivs_init(struct zebra_privs_t *zprivs);
/* drop all and terminate privileges */
extern void zprivs_terminate(struct zebra_privs_t *);
diff --git a/lib/subdir.am b/lib/subdir.am
index 15ce8ec199..6a62cbb678 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -125,7 +125,6 @@ pkginclude_HEADERS += \
lib/ptm_lib.h \
lib/pw.h \
lib/qobj.h \
- lib/route_types.h \
lib/routemap.h \
lib/sbuf.h \
lib/sha256.h \
@@ -142,7 +141,6 @@ pkginclude_HEADERS += \
lib/termtable.h \
lib/thread.h \
lib/vector.h \
- lib/version.h \
lib/vlan.h \
lib/vrf.h \
lib/vrf_int.h \
@@ -155,6 +153,11 @@ pkginclude_HEADERS += \
lib/zebra.h \
# end
+nodist_pkginclude_HEADERS += \
+ lib/route_types.h \
+ lib/version.h \
+ # end
+
noinst_HEADERS += \
lib/clippy.h \
lib/log_int.h \
@@ -181,16 +184,22 @@ lib_libfrrsnmp_la_SOURCES = \
# CLI utilities
#
noinst_PROGRAMS += \
- lib/clippy \
lib/grammar_sandbox \
# end
+if BUILD_CLIPPY
+noinst_PROGRAMS += lib/clippy
+else
+$(HOSTTOOLS)lib/clippy:
+ @$(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/route_types.h lib/clippy
+endif
+
lib_grammar_sandbox_SOURCES = \
lib/grammar_sandbox_main.c
lib_grammar_sandbox_LDADD = \
lib/libfrr.la
-lib_clippy_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib
+lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE
lib_clippy_CFLAGS = $(PYTHON_CFLAGS)
lib_clippy_LDADD = $(PYTHON_LIBS)
lib_clippy_SOURCES = \
@@ -211,6 +220,7 @@ lib_clippy_SOURCES = \
#
EXTRA_DIST += \
lib/command_lex.h \
+ lib/command_parse.h \
lib/gitversion.pl \
lib/queue.h \
lib/route_types.pl \
@@ -218,8 +228,6 @@ EXTRA_DIST += \
# end
BUILT_SOURCES += \
- lib/command_lex.h \
- lib/command_parse.h \
lib/gitversion.h \
lib/route_types.h \
# end
diff --git a/lib/vty.c b/lib/vty.c
index 31fcaf1026..59a8825357 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -1663,24 +1663,82 @@ static struct vty *vty_create(int vty_sock, union sockunion *su)
/* create vty for stdio */
static struct termios stdio_orig_termios;
static struct vty *stdio_vty = NULL;
-static void (*stdio_vty_atclose)(void);
+static bool stdio_termios = false;
+static void (*stdio_vty_atclose)(int isexit);
-static void vty_stdio_reset(void)
+static void vty_stdio_reset(int isexit)
{
if (stdio_vty) {
- tcsetattr(0, TCSANOW, &stdio_orig_termios);
+ if (stdio_termios)
+ tcsetattr(0, TCSANOW, &stdio_orig_termios);
+ stdio_termios = false;
+
stdio_vty = NULL;
if (stdio_vty_atclose)
- stdio_vty_atclose();
+ stdio_vty_atclose(isexit);
stdio_vty_atclose = NULL;
}
}
-struct vty *vty_stdio(void (*atclose)())
+static void vty_stdio_atexit(void)
+{
+ vty_stdio_reset(1);
+}
+
+void vty_stdio_suspend(void)
+{
+ if (!stdio_vty)
+ return;
+
+ if (stdio_vty->t_write)
+ thread_cancel(stdio_vty->t_write);
+ if (stdio_vty->t_read)
+ thread_cancel(stdio_vty->t_read);
+ if (stdio_vty->t_timeout)
+ thread_cancel(stdio_vty->t_timeout);
+
+ if (stdio_termios)
+ tcsetattr(0, TCSANOW, &stdio_orig_termios);
+ stdio_termios = false;
+}
+
+void vty_stdio_resume(void)
+{
+ if (!stdio_vty)
+ return;
+
+ if (!tcgetattr(0, &stdio_orig_termios)) {
+ struct termios termios;
+
+ termios = stdio_orig_termios;
+ termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
+ | IGNCR | ICRNL | IXON);
+ termios.c_oflag &= ~OPOST;
+ termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
+ termios.c_cflag &= ~(CSIZE | PARENB);
+ termios.c_cflag |= CS8;
+ tcsetattr(0, TCSANOW, &termios);
+ stdio_termios = true;
+ }
+
+ vty_prompt(stdio_vty);
+
+ /* Add read/write thread. */
+ vty_event(VTY_WRITE, 1, stdio_vty);
+ vty_event(VTY_READ, 0, stdio_vty);
+}
+
+void vty_stdio_close(void)
+{
+ if (!stdio_vty)
+ return;
+ vty_close(stdio_vty);
+}
+
+struct vty *vty_stdio(void (*atclose)(int isexit))
{
struct vty *vty;
- struct termios termios;
/* refuse creating two vtys on stdio */
if (stdio_vty)
@@ -1698,23 +1756,7 @@ struct vty *vty_stdio(void (*atclose)())
vty->v_timeout = 0;
strcpy(vty->address, "console");
- if (!tcgetattr(0, &stdio_orig_termios)) {
- termios = stdio_orig_termios;
- termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
- | IGNCR | ICRNL | IXON);
- termios.c_oflag &= ~OPOST;
- termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- termios.c_cflag &= ~(CSIZE | PARENB);
- termios.c_cflag |= CS8;
- tcsetattr(0, TCSANOW, &termios);
- }
-
- vty_prompt(vty);
-
- /* Add read/write thread. */
- vty_event(VTY_WRITE, 1, vty);
- vty_event(VTY_READ, 0, vty);
-
+ vty_stdio_resume();
return vty;
}
@@ -1813,7 +1855,7 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
ret = getaddrinfo(hostname, port_str, &req, &ainfo);
if (ret != 0) {
- fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(ret));
+ zlog_err("getaddrinfo failed: %s", gai_strerror(ret));
exit(1);
}
@@ -2163,7 +2205,7 @@ void vty_close(struct vty *vty)
XFREE(MTYPE_VTY, vty);
if (was_stdio)
- vty_stdio_reset();
+ vty_stdio_reset(0);
}
/* When time out occur output message then close connection. */
@@ -2213,23 +2255,22 @@ static void vty_read_file(FILE *confp)
if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) {
const char *message = NULL;
+ char *nl;
+
switch (ret) {
case CMD_ERR_AMBIGUOUS:
- message =
- "*** Error reading config: Ambiguous command.";
+ message = "Ambiguous command";
break;
case CMD_ERR_NO_MATCH:
- message =
- "*** Error reading config: There is no such command.";
+ message = "No such command";
break;
}
- fprintf(stderr, "%s\n", message);
- zlog_err("%s", message);
- fprintf(stderr,
- "*** Error occurred processing line %u, below:\n%s\n",
- line_num, vty->error_buf);
- zlog_err("*** Error occurred processing line %u, below:\n%s",
- line_num, vty->error_buf);
+
+ nl = strchr(vty->error_buf, '\n');
+ if (nl)
+ *nl = '\0';
+ zlog_err("ERROR: %s on config line %u: %s",
+ message, line_num, vty->error_buf);
}
vty_close(vty);
@@ -2301,8 +2342,7 @@ void vty_read_config(const char *config_file, char *config_default_dir)
if (config_file != NULL) {
if (!IS_DIRECTORY_SEP(config_file[0])) {
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- fprintf(stderr,
- "Failure to determine Current Working Directory %d!\n",
+ zlog_err("Failure to determine Current Working Directory %d!",
errno);
exit(1);
}
@@ -2316,17 +2356,14 @@ void vty_read_config(const char *config_file, char *config_default_dir)
confp = fopen(fullpath, "r");
if (confp == NULL) {
- fprintf(stderr,
- "%s: failed to open configuration file %s: %s\n",
+ zlog_err("%s: failed to open configuration file %s: %s",
__func__, fullpath, safe_strerror(errno));
confp = vty_use_backup_config(fullpath);
if (confp)
- fprintf(stderr,
- "WARNING: using backup configuration file!\n");
+ zlog_warn("WARNING: using backup configuration file!");
else {
- fprintf(stderr,
- "can't open configuration file [%s]\n",
+ zlog_err("can't open configuration file [%s]",
config_file);
exit(1);
}
@@ -2361,19 +2398,16 @@ void vty_read_config(const char *config_file, char *config_default_dir)
#endif /* VTYSH */
confp = fopen(config_default_dir, "r");
if (confp == NULL) {
- fprintf(stderr,
- "%s: failed to open configuration file %s: %s\n",
+ zlog_err("%s: failed to open configuration file %s: %s",
__func__, config_default_dir,
safe_strerror(errno));
confp = vty_use_backup_config(config_default_dir);
if (confp) {
- fprintf(stderr,
- "WARNING: using backup configuration file!\n");
+ zlog_warn("WARNING: using backup configuration file!");
fullpath = config_default_dir;
} else {
- fprintf(stderr,
- "can't open configuration file [%s]\n",
+ zlog_err("can't open configuration file [%s]",
config_default_dir);
goto tmp_free_and_out;
}
@@ -2883,12 +2917,12 @@ static void vty_save_cwd(void)
* Hence not worrying about it too much.
*/
if (!chdir(SYSCONFDIR)) {
- fprintf(stderr, "Failure to chdir to %s, errno: %d\n",
+ zlog_err("Failure to chdir to %s, errno: %d",
SYSCONFDIR, errno);
exit(-1);
}
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- fprintf(stderr, "Failure to getcwd, errno: %d\n",
+ zlog_err("Failure to getcwd, errno: %d",
errno);
exit(-1);
}
@@ -2928,7 +2962,7 @@ void vty_init(struct thread_master *master_thread)
vty_master = master_thread;
- atexit(vty_stdio_reset);
+ atexit(vty_stdio_atexit);
/* Initilize server thread vector. */
Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE);
diff --git a/lib/vty.h b/lib/vty.h
index 0980f73afa..dcb8da225d 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -257,7 +257,7 @@ extern void vty_init_vtysh(void);
extern void vty_terminate(void);
extern void vty_reset(void);
extern struct vty *vty_new(void);
-extern struct vty *vty_stdio(void (*atclose)(void));
+extern struct vty *vty_stdio(void (*atclose)(int isexit));
extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
extern void vty_read_config(const char *, char *);
extern void vty_time_print(struct vty *, int);
@@ -273,6 +273,11 @@ extern int vty_shell(struct vty *);
extern int vty_shell_serv(struct vty *);
extern void vty_hello(struct vty *);
+/* ^Z / SIGTSTP handling */
+extern void vty_stdio_suspend(void);
+extern void vty_stdio_resume(void);
+extern void vty_stdio_close(void);
+
/* Send a fixed-size message to all vty terminal monitors; this should be
an async-signal-safe function. */
extern void vty_log_fixed(char *buf, size_t len);
diff --git a/lib/zclient.c b/lib/zclient.c
index 893d769e3a..24cb699196 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -45,7 +45,8 @@ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
/* Prototype for event manager. */
static void zclient_event(enum event, struct zclient *);
-const char *zclient_serv_path = NULL;
+struct sockaddr_storage zclient_addr;
+socklen_t zclient_addr_len;
/* This file local debug flag. */
int zclient_debug = 0;
@@ -183,31 +184,28 @@ void zclient_reset(struct zclient *zclient)
zclient_init(zclient, zclient->redist_default, zclient->instance);
}
-#ifdef HAVE_TCP_ZEBRA
-
-/* Make socket to zebra daemon. Return zebra socket. */
-static int zclient_socket(void)
+/**
+ * Connect to zebra daemon.
+ * @param zclient a pointer to zclient structure
+ * @return socket fd just to make sure that connection established
+ * @see zclient_init
+ * @see zclient_new
+ */
+int zclient_socket_connect(struct zclient *zclient)
{
int sock;
int ret;
- struct sockaddr_in serv;
/* We should think about IPv6 connection. */
- sock = socket(AF_INET, SOCK_STREAM, 0);
+ sock = socket(zclient_addr.ss_family, SOCK_STREAM, 0);
if (sock < 0)
return -1;
- /* Make server socket. */
- memset(&serv, 0, sizeof(struct sockaddr_in));
- serv.sin_family = AF_INET;
- serv.sin_port = htons(ZEBRA_PORT);
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- serv.sin_len = sizeof(struct sockaddr_in);
-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- serv.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ set_cloexec(sock);
/* Connect to zebra. */
- ret = connect(sock, (struct sockaddr *)&serv, sizeof(serv));
+ ret = connect(sock, (struct sockaddr *)&zclient_addr,
+ zclient_addr_len);
if (ret < 0) {
if (zclient_debug)
zlog_warn("%s connect failure: %d(%s)",
@@ -216,65 +214,11 @@ static int zclient_socket(void)
close(sock);
return -1;
}
- return sock;
-}
-#else
-
-/* For sockaddr_un. */
-#include <sys/un.h>
-
-static int zclient_socket_un(const char *path)
-{
- int ret;
- int sock, len;
- struct sockaddr_un addr;
-
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- return -1;
-
- /* Make server socket. */
- memset(&addr, 0, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, path, strlen(path));
-#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
- len = addr.sun_len = SUN_LEN(&addr);
-#else
- len = sizeof(addr.sun_family) + strlen(addr.sun_path);
-#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
-
- ret = connect(sock, (struct sockaddr *)&addr, len);
- if (ret < 0) {
- if (zclient_debug)
- zlog_warn("%s connect failure: %d(%s)",
- __PRETTY_FUNCTION__, errno,
- safe_strerror(errno));
- close(sock);
- return -1;
- }
+ zclient->sock = sock;
return sock;
}
-#endif /* HAVE_TCP_ZEBRA */
-
-/**
- * Connect to zebra daemon.
- * @param zclient a pointer to zclient structure
- * @return socket fd just to make sure that connection established
- * @see zclient_init
- * @see zclient_new
- */
-int zclient_socket_connect(struct zclient *zclient)
-{
-#ifdef HAVE_TCP_ZEBRA
- zclient->sock = zclient_socket();
-#else
- zclient->sock = zclient_socket_un(zclient_serv_path_get());
-#endif
- return zclient->sock;
-}
-
static int zclient_failed(struct zclient *zclient)
{
zclient->fail++;
@@ -2225,34 +2169,6 @@ static void zclient_event(enum event event, struct zclient *zclient)
}
}
-const char *zclient_serv_path_get()
-{
- return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH;
-}
-
-void zclient_serv_path_set(char *path)
-{
- struct stat sb;
-
- /* reset */
- zclient_serv_path = NULL;
-
- /* test if `path' is socket. don't set it otherwise. */
- if (stat(path, &sb) == -1) {
- zlog_warn("%s: zebra socket `%s' does not exist", __func__,
- path);
- return;
- }
-
- if ((sb.st_mode & S_IFMT) != S_IFSOCK) {
- zlog_warn("%s: `%s' is not unix socket, sir", __func__, path);
- return;
- }
-
- /* it seems that path is unix socket */
- zclient_serv_path = path;
-}
-
void zclient_interface_set_master(struct zclient *client,
struct interface *master,
struct interface *slave)
diff --git a/lib/zclient.h b/lib/zclient.h
index 8a2729543f..15d1858d84 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -42,6 +42,14 @@
/* Zebra header size. */
#define ZEBRA_HEADER_SIZE 8
+/* special socket path name to use TCP
+ * @ is used as first character because that's abstract socket names on Linux
+ */
+#define ZAPI_TCP_PATHNAME "@tcp"
+
+extern struct sockaddr_storage zclient_addr;
+extern socklen_t zclient_addr_len;
+
/* Zebra message types. */
typedef enum {
ZEBRA_INTERFACE_ADD,
@@ -103,6 +111,7 @@ typedef enum {
ZEBRA_FEC_REGISTER,
ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE,
+ ZEBRA_ADVERTISE_DEFAULT_GW,
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL,
@@ -297,6 +306,10 @@ struct zapi_pw_status {
uint32_t status;
};
+/* Zebra MAC types */
+#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/
+#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/
+
/* Prototypes of zebra client service functions. */
extern struct zclient *zclient_new(struct thread_master *);
extern void zclient_init(struct zclient *, int, u_short);
@@ -306,8 +319,6 @@ extern void zclient_reset(struct zclient *);
extern void zclient_free(struct zclient *);
extern int zclient_socket_connect(struct zclient *);
-extern void zclient_serv_path_set(char *path);
-extern const char *zclient_serv_path_get(void);
extern u_short *redist_check_instance(struct redist_proto *, u_short);
extern void redist_add_instance(struct redist_proto *, u_short);
diff --git a/nhrpd/.gitignore b/nhrpd/.gitignore
index 3d4d56d589..3f47381278 100644
--- a/nhrpd/.gitignore
+++ b/nhrpd/.gitignore
@@ -1 +1,2 @@
+!Makefile
nhrpd
diff --git a/nhrpd/Makefile b/nhrpd/Makefile
new file mode 100644
index 0000000000..62c9546020
--- /dev/null
+++ b/nhrpd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. nhrpd/nhrpd
+%: ALWAYS
+ @$(MAKE) -s -C .. nhrpd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/nhrpd/Makefile.am b/nhrpd/Makefile.am
deleted file mode 100644
index 64d9e09bfb..0000000000
--- a/nhrpd/Makefile.am
+++ /dev/null
@@ -1,47 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DQUAGGA_NO_DEPRECATED_INTERFACES
-DEFS = @DEFS@ @CARES_CFLAGS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(PICFLAGS) $(WERROR)
-AM_LDFLAGS = $(PICLDFLAGS)
-
-sbin_PROGRAMS = nhrpd
-
-nhrpd_SOURCES = \
- zbuf.c \
- znl.c \
- resolver.c \
- linux.c \
- netlink_arp.c \
- netlink_gre.c \
- vici.c \
- reqid.c \
- nhrp_event.c \
- nhrp_packet.c \
- nhrp_interface.c \
- nhrp_vc.c \
- nhrp_peer.c \
- nhrp_cache.c \
- nhrp_nhs.c \
- nhrp_route.c \
- nhrp_shortcut.c \
- nhrp_vty.c \
- nhrp_main.c
-
-nhrpd_LDADD = ../lib/libfrr.la @LIBCAP@ @CARES_LIBS@
-
-noinst_HEADERS = \
- debug.h \
- list.h \
- netlink.h \
- nhrp_protocol.h \
- nhrpd.h \
- os.h \
- vici.h \
- zbuf.h \
- znl.h \
- # end
-
-#dist_examples_DATA = nhrpd.conf.sample
diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am
new file mode 100644
index 0000000000..5b06946c89
--- /dev/null
+++ b/nhrpd/subdir.am
@@ -0,0 +1,43 @@
+#
+# nhrpd
+#
+
+if NHRPD
+sbin_PROGRAMS += nhrpd/nhrpd
+endif
+
+nhrpd_nhrpd_LDADD = lib/libfrr.la @LIBCAP@ @CARES_LIBS@
+nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) @CARES_CFLAGS@
+nhrpd_nhrpd_SOURCES = \
+ nhrpd/linux.c \
+ nhrpd/netlink_arp.c \
+ nhrpd/netlink_gre.c \
+ nhrpd/nhrp_cache.c \
+ nhrpd/nhrp_event.c \
+ nhrpd/nhrp_interface.c \
+ nhrpd/nhrp_main.c \
+ nhrpd/nhrp_nhs.c \
+ nhrpd/nhrp_packet.c \
+ nhrpd/nhrp_peer.c \
+ nhrpd/nhrp_route.c \
+ nhrpd/nhrp_shortcut.c \
+ nhrpd/nhrp_vc.c \
+ nhrpd/nhrp_vty.c \
+ nhrpd/reqid.c \
+ nhrpd/resolver.c \
+ nhrpd/vici.c \
+ nhrpd/zbuf.c \
+ nhrpd/znl.c \
+ # end
+
+noinst_HEADERS += \
+ nhrpd/debug.h \
+ nhrpd/list.h \
+ nhrpd/netlink.h \
+ nhrpd/nhrp_protocol.h \
+ nhrpd/nhrpd.h \
+ nhrpd/os.h \
+ nhrpd/vici.h \
+ nhrpd/zbuf.h \
+ nhrpd/znl.h \
+ # end
diff --git a/ospf6d/.gitignore b/ospf6d/.gitignore
index 3fef0b7804..744af2d5ce 100644
--- a/ospf6d/.gitignore
+++ b/ospf6d/.gitignore
@@ -1,5 +1,5 @@
+!Makefile
Makefile.in
-Makefile
*.o
*.patch
ospf6d
diff --git a/ospf6d/Makefile b/ospf6d/Makefile
new file mode 100644
index 0000000000..97b37b8c60
--- /dev/null
+++ b/ospf6d/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. ospf6d/ospf6d
+%: ALWAYS
+ @$(MAKE) -s -C .. ospf6d/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am
deleted file mode 100644
index 75dd8ffe46..0000000000
--- a/ospf6d/Makefile.am
+++ /dev/null
@@ -1,43 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(WERROR)
-
-noinst_LIBRARIES = libospf6.a
-module_LTLIBRARIES =
-sbin_PROGRAMS = ospf6d
-
-libospf6_a_SOURCES = \
- ospf6_memory.c \
- ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \
- ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \
- ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \
- ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c \
- ospf6d.c ospf6_bfd.c
-
-noinst_HEADERS = \
- ospf6_memory.h \
- ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \
- ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \
- ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \
- ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h \
- ospf6d.h ospf6_bfd.h
-
-ospf6d_SOURCES = \
- ospf6_main.c $(libospf6_a_SOURCES)
-
-ospf6d_LDADD = ../lib/libfrr.la @LIBCAP@
-
-if SNMP
-module_LTLIBRARIES += ospf6d_snmp.la
-endif
-ospf6d_snmp_la_SOURCES = ospf6_snmp.c
-ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
-ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-ospf6d_snmp_la_LIBADD = ../lib/libfrrsnmp.la
-
-examplesdir = $(exampledir)
-dist_examples_DATA = ospf6d.conf.sample
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
new file mode 100644
index 0000000000..76a64cd637
--- /dev/null
+++ b/ospf6d/subdir.am
@@ -0,0 +1,66 @@
+#
+# ospf6d
+#
+
+if OSPF6D
+noinst_LIBRARIES += ospf6d/libospf6.a
+sbin_PROGRAMS += ospf6d/ospf6d
+dist_examples_DATA += ospf6d/ospf6d.conf.sample
+if SNMP
+module_LTLIBRARIES += ospf6d/ospf6d_snmp.la
+endif
+endif
+
+ospf6d_libospf6_a_SOURCES = \
+ ospf6d/ospf6_abr.c \
+ ospf6d/ospf6_area.c \
+ ospf6d/ospf6_asbr.c \
+ ospf6d/ospf6_bfd.c \
+ ospf6d/ospf6_flood.c \
+ ospf6d/ospf6_interface.c \
+ ospf6d/ospf6_intra.c \
+ ospf6d/ospf6_lsa.c \
+ ospf6d/ospf6_lsdb.c \
+ ospf6d/ospf6_memory.c \
+ ospf6d/ospf6_message.c \
+ ospf6d/ospf6_neighbor.c \
+ ospf6d/ospf6_network.c \
+ ospf6d/ospf6_proto.c \
+ ospf6d/ospf6_route.c \
+ ospf6d/ospf6_spf.c \
+ ospf6d/ospf6_top.c \
+ ospf6d/ospf6_zebra.c \
+ ospf6d/ospf6d.c \
+ # end
+
+noinst_HEADERS += \
+ ospf6d/ospf6_abr.h \
+ ospf6d/ospf6_area.h \
+ ospf6d/ospf6_asbr.h \
+ ospf6d/ospf6_bfd.h \
+ ospf6d/ospf6_flood.h \
+ ospf6d/ospf6_interface.h \
+ ospf6d/ospf6_intra.h \
+ ospf6d/ospf6_lsa.h \
+ ospf6d/ospf6_lsdb.h \
+ ospf6d/ospf6_memory.h \
+ ospf6d/ospf6_message.h \
+ ospf6d/ospf6_neighbor.h \
+ ospf6d/ospf6_network.h \
+ ospf6d/ospf6_proto.h \
+ ospf6d/ospf6_route.h \
+ ospf6d/ospf6_spf.h \
+ ospf6d/ospf6_top.h \
+ ospf6d/ospf6_zebra.h \
+ ospf6d/ospf6d.h \
+ # end
+
+ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la @LIBCAP@
+ospf6d_ospf6d_SOURCES = \
+ ospf6d/ospf6_main.c \
+ # end
+
+ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c
+ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
diff --git a/ospfclient/.gitignore b/ospfclient/.gitignore
index a6000f8021..1740b04fbc 100644
--- a/ospfclient/.gitignore
+++ b/ospfclient/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
ospfclient
diff --git a/ospfclient/Makefile b/ospfclient/Makefile
new file mode 100644
index 0000000000..3da2a5b897
--- /dev/null
+++ b/ospfclient/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. ospfclient/ospfclient
+%: ALWAYS
+ @$(MAKE) -s -C .. ospfclient/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am
deleted file mode 100644
index b4e362bbb3..0000000000
--- a/ospfclient/Makefile.am
+++ /dev/null
@@ -1,28 +0,0 @@
-## Automake.am for OSPF API client
-AUTOMAKE_OPTIONS = subdir-objects
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-AM_CFLAGS = $(WERROR)
-
-lib_LTLIBRARIES = libfrrospfapiclient.la
-libfrrospfapiclient_la_LDFLAGS = -version-info 0:0:0
-libfrrospfapiclient_la_LIBADD = ../lib/libfrr.la
-
-sbin_PROGRAMS = ospfclient
-
-libfrrospfapiclient_la_SOURCES = \
- ospf_apiclient.c
-
-ospfapiheaderdir = $(pkgincludedir)/ospfapi
-
-ospfapiheader_HEADERS = \
- ospf_apiclient.h
-
-ospfclient_SOURCES = \
- ospfclient.c
-
-ospfclient_LDADD = libfrrospfapiclient.la \
- ../lib/libfrr.la @LIBCAP@
-
-ospfclient_CFLAGS = $(AM_CFLAGS)
-ospfclient_LDFLAGS = $(AM_LDFLAGS)
diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c
index 5713105f42..03b543a786 100644
--- a/ospfclient/ospfclient.c
+++ b/ospfclient/ospfclient.c
@@ -307,6 +307,7 @@ int main(int argc, char *argv[])
}
/* Initialization */
+ zprivs_preinit(&ospfd_privs);
zprivs_init(&ospfd_privs);
master = thread_master_create(NULL);
diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am
new file mode 100644
index 0000000000..834d4aaba7
--- /dev/null
+++ b/ospfclient/subdir.am
@@ -0,0 +1,30 @@
+#
+# ospfclient
+#
+
+if OSPFCLIENT
+lib_LTLIBRARIES += ospfclient/libfrrospfapiclient.la
+sbin_PROGRAMS += ospfclient/ospfclient
+endif
+
+ospfclient_libfrrospfapiclient_la_LDFLAGS = -version-info 0:0:0
+ospfclient_libfrrospfapiclient_la_LIBADD = lib/libfrr.la
+ospfclient_libfrrospfapiclient_la_SOURCES = \
+ ospfclient/ospf_apiclient.c \
+ # end
+
+if OSPFCLIENT
+ospfapiheaderdir = $(pkgincludedir)/ospfapi
+ospfapiheader_HEADERS = \
+ ospfclient/ospf_apiclient.h \
+ # end
+endif
+
+ospfclient_ospfclient_LDADD = \
+ ospfclient/libfrrospfapiclient.la \
+ lib/libfrr.la \
+ @LIBCAP@ \
+ # end
+ospfclient_ospfclient_SOURCES = \
+ ospfclient/ospfclient.c \
+ # end
diff --git a/ospfd/.gitignore b/ospfd/.gitignore
index 4b8787c89e..752c875a62 100644
--- a/ospfd/.gitignore
+++ b/ospfd/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
ospfd
diff --git a/ospfd/Makefile b/ospfd/Makefile
new file mode 100644
index 0000000000..e4fab30e19
--- /dev/null
+++ b/ospfd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. ospfd/ospfd
+%: ALWAYS
+ @$(MAKE) -s -C .. ospfd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am
deleted file mode 100644
index c6a5ec91d2..0000000000
--- a/ospfd/Makefile.am
+++ /dev/null
@@ -1,49 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-AM_CFLAGS = $(WERROR)
-DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-noinst_LIBRARIES = libfrrospf.a
-module_LTLIBRARIES =
-sbin_PROGRAMS = ospfd
-
-libfrrospf_a_SOURCES = \
- ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \
- ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \
- ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \
- ospf_lsdb.c ospf_asbr.c ospf_routemap.c \
- ospf_opaque.c ospf_te.c ospf_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c \
- ospf_bfd.c ospf_memory.c ospf_dump_api.c
-
-ospfdheaderdir = $(pkgincludedir)/ospfd
-
-ospfdheader_HEADERS = \
- ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \
- ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h \
- ospf_dump_api.h
-
-noinst_HEADERS = \
- ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \
- ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \
- ospf_flood.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.h \
- ospf_bfd.h ospf_memory.h
-
-ospfd_SOURCES = ospf_main.c
-
-ospfd_LDADD = libfrrospf.a ../lib/libfrr.la @LIBCAP@ @LIBM@
-
-if SNMP
-module_LTLIBRARIES += ospfd_snmp.la
-endif
-ospfd_snmp_la_SOURCES = ospf_snmp.c
-ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
-ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-ospfd_snmp_la_LIBADD = ../lib/libfrrsnmp.la
-
-EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt
-
-examplesdir = $(exampledir)
-dist_examples_DATA = ospfd.conf.sample
-
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
new file mode 100644
index 0000000000..12c2313e65
--- /dev/null
+++ b/ospfd/subdir.am
@@ -0,0 +1,93 @@
+#
+# ospfd
+#
+
+if OSPFD
+noinst_LIBRARIES += ospfd/libfrrospf.a
+sbin_PROGRAMS += ospfd/ospfd
+dist_examples_DATA += ospfd/ospfd.conf.sample
+if SNMP
+module_LTLIBRARIES += ospfd/ospfd_snmp.la
+endif
+endif
+
+ospfd_libfrrospf_a_SOURCES = \
+ ospfd/ospf_abr.c \
+ ospfd/ospf_api.c \
+ ospfd/ospf_apiserver.c \
+ ospfd/ospf_asbr.c \
+ ospfd/ospf_ase.c \
+ ospfd/ospf_bfd.c \
+ ospfd/ospf_dump.c \
+ ospfd/ospf_dump_api.c \
+ ospfd/ospf_flood.c \
+ ospfd/ospf_ia.c \
+ ospfd/ospf_interface.c \
+ ospfd/ospf_ism.c \
+ ospfd/ospf_lsa.c \
+ ospfd/ospf_lsdb.c \
+ ospfd/ospf_memory.c \
+ ospfd/ospf_neighbor.c \
+ ospfd/ospf_network.c \
+ ospfd/ospf_nsm.c \
+ ospfd/ospf_opaque.c \
+ ospfd/ospf_packet.c \
+ ospfd/ospf_ri.c \
+ ospfd/ospf_route.c \
+ ospfd/ospf_routemap.c \
+ ospfd/ospf_spf.c \
+ ospfd/ospf_te.c \
+ ospfd/ospf_vty.c \
+ ospfd/ospf_zebra.c \
+ ospfd/ospfd.c \
+ # end
+
+if OSPFD
+ospfdheaderdir = $(pkgincludedir)/ospfd
+ospfdheader_HEADERS = \
+ ospfd/ospf_api.h \
+ ospfd/ospf_asbr.h \
+ ospfd/ospf_dump.h \
+ ospfd/ospf_dump_api.h \
+ ospfd/ospf_ism.h \
+ ospfd/ospf_lsa.h \
+ ospfd/ospf_lsdb.h \
+ ospfd/ospf_nsm.h \
+ ospfd/ospf_opaque.h \
+ ospfd/ospfd.h \
+ # end
+endif
+
+noinst_HEADERS += \
+ ospfd/ospf_abr.h \
+ ospfd/ospf_apiserver.h \
+ ospfd/ospf_ase.h \
+ ospfd/ospf_bfd.h \
+ ospfd/ospf_flood.h \
+ ospfd/ospf_ia.h \
+ ospfd/ospf_interface.h \
+ ospfd/ospf_memory.h \
+ ospfd/ospf_neighbor.h \
+ ospfd/ospf_network.h \
+ ospfd/ospf_packet.h \
+ ospfd/ospf_ri.h \
+ ospfd/ospf_route.h \
+ ospfd/ospf_spf.h \
+ ospfd/ospf_te.h \
+ ospfd/ospf_vty.h \
+ ospfd/ospf_zebra.h \
+ # end
+
+ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la @LIBCAP@ @LIBM@
+ospfd_ospfd_SOURCES = ospfd/ospf_main.c
+
+ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c
+ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la
+
+EXTRA_DIST += \
+ ospfd/ChangeLog.opaque.txt \
+ ospfd/OSPF-MIB.txt \
+ ospfd/OSPF-TRAP-MIB.txt \
+ # end
diff --git a/qpb/subdir.am b/qpb/subdir.am
index 71e501b9c2..3c006fd221 100644
--- a/qpb/subdir.am
+++ b/qpb/subdir.am
@@ -16,7 +16,6 @@ qpb_libfrr_pb_la_SOURCES = \
if HAVE_PROTOBUF
qpb_libfrr_pb_la_SOURCES += qpb/qpb_allocator.c
nodist_qpb_libfrr_pb_la_SOURCES = qpb/qpb.pb-c.c
-BUILT_SOURCES += qpb/qpb.pb-c.c
CLEANFILES += \
qpb/qpb.pb-c.c \
qpb/qpb.pb-c.h \
diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md
index dd01babf50..c05331256a 100644
--- a/redhat/README.rpm_build.md
+++ b/redhat/README.rpm_build.md
@@ -52,7 +52,6 @@ Building your own FRRouting RPM
############### FRRouting (FRR) configure options #################
# with-feature options
- %{!?with_tcp_zebra: %global with_tcp_zebra 0 }
%{!?with_pam: %global with_pam 0 }
%{!?with_ospfclient: %global with_ospfclient 1 }
%{!?with_ospfapi: %global with_ospfapi 1 }
diff --git a/redhat/daemons b/redhat/daemons
index 94d6c72c30..8d12a1f5b8 100644
--- a/redhat/daemons
+++ b/redhat/daemons
@@ -35,7 +35,7 @@
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
watchfrr_enable=no
-watchfrr_options=("-Az" "-b_" "-r/etc/init.d/frr_restart_%s" "-s/etc/init.d/frr_start_%s" "-k/etc/init.d/frr_stop_%s")
+watchfrr_options=("-b_" "-r/etc/init.d/frr_restart_%s" "-s/etc/init.d/frr_start_%s" "-k/etc/init.d/frr_stop_%s")
#
zebra=no
bgpd=no
diff --git a/redhat/frr.logrotate b/redhat/frr.logrotate
index f43a86efe7..25a5587787 100644
--- a/redhat/frr.logrotate
+++ b/redhat/frr.logrotate
@@ -1,3 +1,11 @@
+/var/log/frr/frr.log {
+ notifempty
+ missingok
+ postrotate
+ /bin/kill -HUP `cat /var/run/*syslog*.pid 2> /dev/null` 2> /dev/null || true
+ endscript
+}
+
/var/log/frr/zebra.log {
notifempty
missingok
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index b23249e04e..12cdcf04fe 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -10,7 +10,6 @@
#################### FRRouting (FRR) configure options #####################
# with-feature options
-%{!?with_tcp_zebra: %global with_tcp_zebra 0 }
%{!?with_pam: %global with_pam 0 }
%{!?with_ospfclient: %global with_ospfclient 1 }
%{!?with_ospfapi: %global with_ospfapi 1 }
@@ -75,12 +74,6 @@
%global with_pimd 0
%endif
-# if FPM is enabled, then enable tcp_zebra as well
-#
-%if %{with_fpm}
- %global with_tcp_zebra 1
-%endif
-
# misc internal defines
%{!?frr_uid: %global frr_uid 92 }
%{!?frr_gid: %global frr_gid 92 }
@@ -234,9 +227,6 @@ developing OSPF-API and frr applications.
%if %{with_multipath}
--enable-multipath=%{with_multipath} \
%endif
-%if %{with_tcp_zebra}
- --enable-tcp-zebra \
-%endif
--enable-vtysh \
%if %{with_ospfclient}
--enable-ospfclient \
diff --git a/ripd/.gitignore b/ripd/.gitignore
index 9bcfb635e5..177250ca61 100644
--- a/ripd/.gitignore
+++ b/ripd/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
ripd
diff --git a/ripd/Makefile b/ripd/Makefile
new file mode 100644
index 0000000000..2d6f838d0a
--- /dev/null
+++ b/ripd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. ripd/ripd
+%: ALWAYS
+ @$(MAKE) -s -C .. ripd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/ripd/Makefile.am b/ripd/Makefile.am
deleted file mode 100644
index 9c034f0c38..0000000000
--- a/ripd/Makefile.am
+++ /dev/null
@@ -1,39 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(WERROR)
-
-noinst_LIBRARIES = librip.a
-module_LTLIBRARIES =
-sbin_PROGRAMS = ripd
-
-librip_a_SOURCES = \
- rip_memory.c \
- ripd.c rip_zebra.c rip_interface.c rip_debug.c \
- rip_routemap.c rip_peer.c rip_offset.c
-
-noinst_HEADERS = \
- rip_memory.h \
- ripd.h rip_debug.h rip_interface.h
-
-ripd_SOURCES = \
- rip_main.c $(librip_a_SOURCES)
-
-ripd_LDADD = ../lib/libfrr.la @LIBCAP@
-
-if SNMP
-module_LTLIBRARIES += ripd_snmp.la
-endif
-ripd_snmp_la_SOURCES = rip_snmp.c
-ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
-ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-ripd_snmp_la_LIBADD = ../lib/libfrrsnmp.la
-
-examplesdir = $(exampledir)
-dist_examples_DATA = ripd.conf.sample
-
-EXTRA_DIST = RIPv2-MIB.txt
-
diff --git a/ripd/subdir.am b/ripd/subdir.am
new file mode 100644
index 0000000000..7a8f2185ba
--- /dev/null
+++ b/ripd/subdir.am
@@ -0,0 +1,42 @@
+#
+# ripd
+#
+
+if RIPD
+noinst_LIBRARIES += ripd/librip.a
+sbin_PROGRAMS += ripd/ripd
+dist_examples_DATA += ripd/ripd.conf.sample
+if SNMP
+module_LTLIBRARIES += ripd/ripd_snmp.la
+endif
+endif
+
+ripd_librip_a_SOURCES = \
+ ripd/rip_debug.c \
+ ripd/rip_interface.c \
+ ripd/rip_memory.c \
+ ripd/rip_offset.c \
+ ripd/rip_peer.c \
+ ripd/rip_routemap.c \
+ ripd/rip_zebra.c \
+ ripd/ripd.c \
+ # end
+
+noinst_HEADERS += \
+ ripd/rip_debug.h \
+ ripd/rip_interface.h \
+ ripd/rip_memory.h \
+ ripd/ripd.h \
+ # end
+
+ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@
+ripd_ripd_SOURCES = \
+ ripd/rip_main.c \
+ # end
+
+ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
+ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la
+
+EXTRA_DIST += ripd/RIPv2-MIB.txt
diff --git a/ripngd/.gitignore b/ripngd/.gitignore
index e871fae3ed..213384d139 100644
--- a/ripngd/.gitignore
+++ b/ripngd/.gitignore
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
Makefile.in
*.o
ripngd
diff --git a/ripngd/Makefile b/ripngd/Makefile
new file mode 100644
index 0000000000..5b76bb2b40
--- /dev/null
+++ b/ripngd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. ripngd/ripngd
+%: ALWAYS
+ @$(MAKE) -s -C .. ripngd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am
deleted file mode 100644
index 3a4be999a7..0000000000
--- a/ripngd/Makefile.am
+++ /dev/null
@@ -1,28 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-AM_CFLAGS = $(WERROR)
-
-noinst_LIBRARIES = libripng.a
-sbin_PROGRAMS = ripngd
-
-libripng_a_SOURCES = \
- ripng_memory.c \
- ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \
- ripng_routemap.c ripng_offset.c ripng_peer.c ripng_nexthop.c
-
-noinst_HEADERS = \
- ripng_memory.h \
- ripng_debug.h ripng_route.h ripngd.h ripng_nexthop.h
-
-ripngd_SOURCES = \
- ripng_main.c $(libripng_a_SOURCES)
-
-ripngd_LDADD = ../lib/libfrr.la @LIBCAP@
-
-examplesdir = $(exampledir)
-dist_examples_DATA = ripngd.conf.sample
-
diff --git a/ripngd/subdir.am b/ripngd/subdir.am
new file mode 100644
index 0000000000..1f7ff09d6e
--- /dev/null
+++ b/ripngd/subdir.am
@@ -0,0 +1,36 @@
+#
+# ripngd
+#
+
+if RIPNGD
+noinst_LIBRARIES += ripngd/libripng.a
+sbin_PROGRAMS += ripngd/ripngd
+endif
+
+ripngd_libripng_a_SOURCES = \
+ ripngd/ripng_debug.c \
+ ripngd/ripng_interface.c \
+ ripngd/ripng_memory.c \
+ ripngd/ripng_nexthop.c \
+ ripngd/ripng_offset.c \
+ ripngd/ripng_peer.c \
+ ripngd/ripng_route.c \
+ ripngd/ripng_routemap.c \
+ ripngd/ripng_zebra.c \
+ ripngd/ripngd.c \
+ # end
+
+noinst_HEADERS += \
+ ripngd/ripng_debug.h \
+ ripngd/ripng_memory.h \
+ ripngd/ripng_nexthop.h \
+ ripngd/ripng_route.h \
+ ripngd/ripngd.h \
+ # end
+
+ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la @LIBCAP@
+ripngd_ripngd_SOURCES = \
+ ripngd/ripng_main.c \
+ # end
+
+dist_examples_DATA += ripngd/ripngd.conf.sample
diff --git a/tests/.gitignore b/tests/.gitignore
index 113bdea098..604ffaa8b6 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -19,7 +19,6 @@ TAGS
.arch-inventory
.arch-ids
__pycache__
-.dirstamp
/bgpd/test_aspath
/bgpd/test_capability
/bgpd/test_ecommunity
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0c31c0441a..59ea3c4c69 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -85,9 +85,7 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
-
-BUILT_SOURCES = \
- lib/cli/test_commands_defun.c \
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
isisd/test_fuzz_isis_tlv_tests.h
noinst_HEADERS = \
diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c
index b6df6d3b8d..77f1610fe2 100644
--- a/tests/lib/cli/common_cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -45,7 +45,7 @@ int dump_args(struct vty *vty, const char *descr, int argc,
return CMD_SUCCESS;
}
-static void vty_do_exit(void)
+static void vty_do_exit(int isexit)
{
printf("\nend.\n");
cmd_terminate();
@@ -54,7 +54,8 @@ static void vty_do_exit(void)
closezlog();
log_memstats_stderr("testcli");
- exit(0);
+ if (!isexit)
+ exit(0);
}
/* main routine. */
diff --git a/tests/lib/test_privs.c b/tests/lib/test_privs.c
index c2cb5c2ea5..1984f28e63 100644
--- a/tests/lib/test_privs.c
+++ b/tests/lib/test_privs.c
@@ -108,6 +108,7 @@ int main(int argc, char **argv)
/* Library inits. */
memory_init();
+ zprivs_preinit(&test_privs);
zprivs_init(&test_privs);
#define PRIV_STATE() \
diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c
index afc5ba6630..5e604db61a 100644
--- a/tests/test_lblmgr.c
+++ b/tests/test_lblmgr.c
@@ -113,8 +113,7 @@ static int zebra_send_release_label_chunk(uint32_t start, uint32_t end)
void init_zclient(struct thread_master *master, char *lm_zserv_path)
{
- if (lm_zserv_path)
- zclient_serv_path_set(lm_zserv_path);
+ frr_zclient_addr(&zclient_addr, &zclient_addr_len, lm_zserv_path);
zclient = zclient_new(master);
/* zclient_init(zclient, ZEBRA_LABEL_MANAGER, 0); */
diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf
index 3f734eef02..0d92d13671 100644
--- a/tools/etc/frr/daemons.conf
+++ b/tools/etc/frr/daemons.conf
@@ -19,7 +19,7 @@ babeld_options=" --daemon -A 127.0.0.1"
# The list of daemons to watch is automatically generated by the init script.
watchfrr_enable=yes
-watchfrr_options=(-adz -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30)
+watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30)
# If valgrind_enable is 'yes' the frr daemons will be started via valgrind.
# The use case for doing so is tracking down memory leaks, etc in frr.
diff --git a/tools/etc/frr/frr.conf b/tools/etc/frr/frr.conf
index 2cd05bf803..61f7a65620 100644
--- a/tools/etc/frr/frr.conf
+++ b/tools/etc/frr/frr.conf
@@ -1,2 +1,3 @@
-log file /var/log/frr/frr.log
-log timestamp precision 6
+# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log
+# in /var/log/frr/frr.log
+log syslog informational
diff --git a/tools/etc/rsyslog.d/45-frr.conf b/tools/etc/rsyslog.d/45-frr.conf
new file mode 100644
index 0000000000..ff7cd48318
--- /dev/null
+++ b/tools/etc/rsyslog.d/45-frr.conf
@@ -0,0 +1,36 @@
+# The lines below cause all FRR daemons and process to go
+# to /var/log/frr/frr.log, then drops the message so it does
+# not also go to /var/log/syslog, so the messages are not duplicated
+
+$outchannel frr_log,/var/log/frr/frr.log
+if $programname == 'babeld' or
+ $programname == 'bgpd' or
+ $programname == 'eigrpd' or
+ $programname == 'frr' or
+ $programname == 'isisd' or
+ $programname == 'ldpd' or
+ $programname == 'nhrpd' or
+ $programname == 'ospf6d' or
+ $programname == 'ospfd' or
+ $programname == 'pimd' or
+ $programname == 'ripd' or
+ $programname == 'ripngd' or
+ $programname == 'watchfrr' or
+ $programname == 'zebra'
+ then :omfile:$frr_log
+
+if $programname == 'babeld' or
+ $programname == 'bgpd' or
+ $programname == 'eigrpd' or
+ $programname == 'frr' or
+ $programname == 'isisd' or
+ $programname == 'ldpd' or
+ $programname == 'nhrpd' or
+ $programname == 'ospf6d' or
+ $programname == 'ospfd' or
+ $programname == 'pimd' or
+ $programname == 'ripd' or
+ $programname == 'ripngd' or
+ $programname == 'watchfrr' or
+ $programname == 'zebra'
+ then stop
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index bfdc08ab4c..43496d4cbf 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -432,6 +432,8 @@ end
ctx_keys.append("address-family ipv6 unicast")
elif line == "address-family ipv4":
ctx_keys.append("address-family ipv4 unicast")
+ elif line == "address-family evpn":
+ ctx_keys.append("address-family l2vpn evpn")
else:
ctx_keys.append(line)
@@ -745,6 +747,37 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_del_to_del.append((ctx_keys, None))
lines_to_add_to_del.append(((tmpline,), None))
+ if (len(ctx_keys) == 3 and
+ ctx_keys[0].startswith('router bgp') and
+ ctx_keys[1] == 'address-family l2vpn evpn' and
+ ctx_keys[2].startswith('vni')):
+
+ re_route_target = re.search('^route-target import (.*)$', line) if line is not None else False
+
+ if re_route_target:
+ rt = re_route_target.group(1).strip()
+ route_target_import_line = line
+ route_target_export_line = "route-target export %s" % rt
+ route_target_both_line = "route-target both %s" % rt
+
+ found_route_target_export_line = line_exist(lines_to_del, ctx_keys, route_target_export_line)
+ found_route_target_both_line = line_exist(lines_to_add, ctx_keys, route_target_both_line)
+
+ '''
+ If the running configs has
+ route-target import 1:1
+ route-target export 1:1
+
+ and the config we are reloading against has
+ route-target both 1:1
+
+ then we can ignore deleting the import/export and ignore adding the 'both'
+ '''
+ if found_route_target_export_line and found_route_target_both_line:
+ lines_to_del_to_del.append((ctx_keys, route_target_import_line))
+ lines_to_del_to_del.append((ctx_keys, route_target_export_line))
+ lines_to_add_to_del.append((ctx_keys, route_target_both_line))
+
if not deleted:
found_add_line = line_exist(lines_to_add, ctx_keys, line)
@@ -822,6 +855,13 @@ def compare_context_objects(newconf, running):
elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd:
continue
+ # Delete an entire vni sub-context under "address-family l2vpn evpn"
+ elif ("router bgp" in running_ctx_keys[0] and
+ len(running_ctx_keys) > 2 and
+ running_ctx_keys[1].startswith('address-family l2vpn evpn') and
+ running_ctx_keys[2].startswith('vni ')):
+ lines_to_del.append((running_ctx_keys, None))
+
elif ("router bgp" in running_ctx_keys[0] and
len(running_ctx_keys) > 1 and
running_ctx_keys[1].startswith('address-family')):
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 76c42173da..6255726c47 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1164,10 +1164,10 @@ DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
}
#if defined(HAVE_CUMULUS)
-DEFUNSH(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd,
- "address-family evpn",
- "Enter Address Family command mode\n"
- "EVPN Address family\n")
+DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd,
+ "address-family evpn",
+ "Enter Address Family command mode\n"
+ "EVPN Address family\n")
{
vty->node = BGP_EVPN_NODE;
return CMD_SUCCESS;
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 43aff0e3a5..c561b5222f 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -224,6 +224,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
strlen("ipv6 access-list"))
== 0)
config = config_get(ACCESS_IPV6_NODE, line);
+ else if (strncmp(line, "mac access-list",
+ strlen("mac access-list"))
+ == 0)
+ config = config_get(ACCESS_MAC_NODE, line);
else if (strncmp(line, "ip prefix-list",
strlen("ip prefix-list"))
== 0)
@@ -302,9 +306,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
#define NO_DELIMITER(I) \
((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
|| (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
- || (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
- || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
- || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
+ || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
+ || (I) == PREFIX_IPV6_NODE || (I) == SERVICE_NODE \
+ || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
+ || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
/* Display configuration to file pointer. */
void vtysh_config_dump(FILE *fp)
diff --git a/watchfrr/Makefile.am b/watchfrr/Makefile.am
index abe2266f20..bb53641eff 100644
--- a/watchfrr/Makefile.am
+++ b/watchfrr/Makefile.am
@@ -1,8 +1,6 @@
## Process this file with Automake to create Makefile.in
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\"
-
AM_CFLAGS = $(WERROR)
sbin_PROGRAMS = watchfrr
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index 6adb25f322..c9f721eacb 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -50,37 +50,14 @@
#define DEFAULT_LOGLEVEL LOG_INFO
#define DEFAULT_MIN_RESTART 60
#define DEFAULT_MAX_RESTART 600
-#ifdef PATH_WATCHFRR_PID
-#define DEFAULT_PIDFILE PATH_WATCHFRR_PID
-#else
-#define DEFAULT_PIDFILE STATEDIR "/watchfrr.pid"
-#endif
-#ifdef DAEMON_VTY_DIR
-#define VTYDIR DAEMON_VTY_DIR
-#else
-#define VTYDIR STATEDIR
-#endif
#define PING_TOKEN "PING"
/* Needs to be global, referenced somewhere inside libfrr. */
struct thread_master *master;
+static char pidfile_default[256];
-typedef enum {
- MODE_MONITOR = 0,
- MODE_GLOBAL_RESTART,
- MODE_SEPARATE_RESTART,
- MODE_PHASED_ZEBRA_RESTART,
- MODE_PHASED_ALL_RESTART
-} watch_mode_t;
-
-static const char *mode_str[] = {
- "monitor",
- "global restart",
- "individual daemon restart",
- "phased zebra restart",
- "phased global restart for any failure",
-};
+static bool watch_only = false;
typedef enum {
PHASE_NONE = 0,
@@ -112,7 +89,6 @@ struct restart_info {
};
static struct global_state {
- watch_mode_t mode;
restart_phase_t phase;
struct thread *t_phase_hanging;
const char *vtydir;
@@ -121,29 +97,25 @@ static struct global_state {
long restart_timeout;
long min_restart_interval;
long max_restart_interval;
- int do_ping;
struct daemon *daemons;
const char *restart_command;
const char *start_command;
const char *stop_command;
struct restart_info restart;
- int unresponsive_restart;
int loglevel;
struct daemon *special; /* points to zebra when doing phased restart */
int numdaemons;
int numpids;
int numdown; /* # of daemons that are not UP or UNRESPONSIVE */
} gs = {
- .mode = MODE_MONITOR,
.phase = PHASE_NONE,
- .vtydir = VTYDIR,
+ .vtydir = frr_vtydir,
.period = 1000 * DEFAULT_PERIOD,
.timeout = DEFAULT_TIMEOUT,
.restart_timeout = DEFAULT_RESTART_TIMEOUT,
.loglevel = DEFAULT_LOGLEVEL,
.min_restart_interval = DEFAULT_MIN_RESTART,
.max_restart_interval = DEFAULT_MAX_RESTART,
- .do_ping = 1,
};
typedef enum {
@@ -176,11 +148,11 @@ struct daemon {
#define OPTION_MINRESTART 2000
#define OPTION_MAXRESTART 2001
+#define OPTION_DRY 2002
static const struct option longopts[] = {
{"daemon", no_argument, NULL, 'd'},
{"statedir", required_argument, NULL, 'S'},
- {"no-echo", no_argument, NULL, 'e'},
{"loglevel", required_argument, NULL, 'l'},
{"interval", required_argument, NULL, 'i'},
{"timeout", required_argument, NULL, 't'},
@@ -188,10 +160,7 @@ static const struct option longopts[] = {
{"restart", required_argument, NULL, 'r'},
{"start-command", required_argument, NULL, 's'},
{"kill-command", required_argument, NULL, 'k'},
- {"restart-all", required_argument, NULL, 'R'},
- {"all-restart", no_argument, NULL, 'a'},
- {"always-all-restart", no_argument, NULL, 'A'},
- {"unresponsive-restart", no_argument, NULL, 'z'},
+ {"dry", no_argument, NULL, OPTION_DRY},
{"min-restart-interval", required_argument, NULL, OPTION_MINRESTART},
{"max-restart-interval", required_argument, NULL, OPTION_MAXRESTART},
{"pid-file", required_argument, NULL, 'p'},
@@ -217,55 +186,19 @@ It then repeatedly sends echo commands over that socket to determine whether\n\
the daemon is responsive. If the daemon crashes, we will receive an EOF\n\
on the socket connection and know immediately that the daemon is down.\n\n\
The daemons to be monitored should be listed on the command line.\n\n\
-This program can run in one of 5 modes:\n\n\
-0. Mode: %s.\n\
- Just monitor and report on status changes. Example:\n\
- %s -d zebra ospfd bgpd\n\n\
-1. Mode: %s.\n\
- Whenever any daemon hangs or crashes, use the given command to restart\n\
- them all. Example:\n\
- %s -dz \\\n\
- -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\
- zebra ospfd\n\n\
-2. Mode: %s.\n\
- When any single daemon hangs or crashes, restart only the daemon that's\n\
- in trouble using the supplied restart command. Example:\n\
- %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\
-3. Mode: %s.\n\
- The same as the previous mode, except that there is special treatment when\n\
- the zebra daemon is in trouble. In that case, a phased restart approach\n\
- is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\
- daemons. Example:\n\
- %s -adz -r '/sbin/service %%s restart' \\\n\
- -s '/sbin/service %%s start' \\\n\
- -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\
-4. Mode: %s.\n\
- This is the same as the previous mode, except that the phased restart\n\
- procedure is used whenever any of the daemons hangs or crashes. Example:\n\
- %s -Adz -r '/sbin/service %%s restart' \\\n\
- -s '/sbin/service %%s start' \\\n\
- -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\
-As of this writing, it is believed that mode 2 [%s]\n\
-is not safe, and mode 3 [%s] may not be safe with some of the\n\
-routing daemons.\n\n\
In order to avoid attempting to restart the daemons in a fast loop,\n\
the -m and -M options allow you to control the minimum delay between\n\
restart commands. The minimum restart delay is recalculated each time\n\
a restart is attempted: if the time since the last restart attempt exceeds\n\
twice the -M value, then the restart delay is set to the -m value.\n\
Otherwise, the interval is doubled (but capped at the -M value).\n\n",
- progname, mode_str[0], progname, mode_str[1], progname,
- mode_str[2], progname, mode_str[3], progname, mode_str[4],
- progname, mode_str[2], mode_str[3]);
+ progname);
fprintf(target,
"Options:\n\
-d, --daemon Run in daemon mode. In this mode, error messages are sent\n\
to syslog instead of stdout.\n\
-S, --statedir Set the vty socket directory (default is %s)\n\
--e, --no-echo Do not ping the daemons to test responsiveness (this\n\
- option is necessary if the daemons do not support the\n\
- echo command)\n\
-l, --loglevel Set the logging level (default is %d).\n\
The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\
but it can be set higher than %d if extra-verbose debugging\n\
@@ -285,7 +218,6 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n",
-r, --restart Supply a Bourne shell command to use to restart a single\n\
daemon. The command string should include '%%s' where the\n\
name of the daemon should be substituted.\n\
- Note that -r and -R are incompatible.\n\
-s, --start-command\n\
Supply a Bourne shell to command to use to start a single\n\
daemon. The command string should include '%%s' where the\n\
@@ -294,33 +226,19 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n",
Supply a Bourne shell to command to use to stop a single\n\
daemon. The command string should include '%%s' where the\n\
name of the daemon should be substituted.\n\
--R, --restart-all\n\
- When one or more daemons is down, try to restart everything\n\
- using the Bourne shell command supplied as the argument.\n\
- Note that -r and -R are incompatible.\n\
--z, --unresponsive-restart\n\
- When a daemon is unresponsive, treat it as being down for\n\
- restart purposes.\n\
--a, --all-restart\n\
- When zebra hangs or crashes, restart all daemons using\n\
- this phased approach: 1. stop all other daemons; 2. restart\n\
- zebra; 3. start other daemons. Requires -r, -s, and -k.\n\
--A, --always-all-restart\n\
- When any daemon (not just zebra) hangs or crashes, use the\n\
- same phased restart mechanism described above for -a.\n\
- Requires -r, -s, and -k.\n\
+ --dry Do not start or restart anything, just log.\n\
-p, --pid-file Set process identifier file name\n\
(default is %s).\n\
-b, --blank-string\n\
When the supplied argument string is found in any of the\n\
- various shell command arguments (-r, -s, -k, or -R), replace\n\
+ various shell command arguments (-r, -s, or -k), replace\n\
it with a space. This is an ugly hack to circumvent problems\n\
passing command-line arguments with embedded spaces.\n\
-v, --version Print program version\n\
-h, --help Display this help and exit\n",
- VTYDIR, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG,
+ frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG,
DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_PERIOD,
- DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, DEFAULT_PIDFILE);
+ DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, pidfile_default);
}
static pid_t run_background(char *shell_cmd)
@@ -390,15 +308,10 @@ static int restart_kill(struct thread *t_kill)
static struct restart_info *find_child(pid_t child)
{
- if (gs.mode == MODE_GLOBAL_RESTART) {
- if (gs.restart.pid == child)
- return &gs.restart;
- } else {
- struct daemon *dmn;
- for (dmn = gs.daemons; dmn; dmn = dmn->next) {
- if (dmn->restart.pid == child)
- return &dmn->restart;
- }
+ struct daemon *dmn;
+ for (dmn = gs.daemons; dmn; dmn = dmn->next) {
+ if (dmn->restart.pid == child)
+ return &dmn->restart;
}
return NULL;
}
@@ -700,8 +613,7 @@ static void daemon_up(struct daemon *dmn, const char *why)
dmn->connect_tries = 0;
zlog_notice("%s state -> up : %s", dmn->name, why);
daemon_send_ready();
- if (gs.do_ping)
- SET_WAKEUP_ECHO(dmn);
+ SET_WAKEUP_ECHO(dmn);
phase_check();
}
@@ -889,61 +801,46 @@ static void phase_check(void)
static void try_restart(struct daemon *dmn)
{
- switch (gs.mode) {
- case MODE_MONITOR:
+ if (watch_only)
return;
- case MODE_GLOBAL_RESTART:
- run_job(&gs.restart, "restart", gs.restart_command, 0, 1);
- break;
- case MODE_SEPARATE_RESTART:
- run_job(&dmn->restart, "restart", gs.restart_command, 0, 1);
- break;
- case MODE_PHASED_ZEBRA_RESTART:
- if (dmn != gs.special) {
- if ((gs.special->state == DAEMON_UP)
- && (gs.phase == PHASE_NONE))
- run_job(&dmn->restart, "restart",
- gs.restart_command, 0, 1);
- else
- zlog_debug(
- "%s: postponing restart attempt because master %s daemon "
- "not up [%s], or phased restart in progress",
- dmn->name, gs.special->name,
- state_str[gs.special->state]);
- break;
- }
- /*FALLTHRU*/
- case MODE_PHASED_ALL_RESTART:
- if ((gs.phase != PHASE_NONE) || gs.numpids) {
+ if (dmn != gs.special) {
+ if ((gs.special->state == DAEMON_UP)
+ && (gs.phase == PHASE_NONE))
+ run_job(&dmn->restart, "restart", gs.restart_command, 0,
+ 1);
+ else
+ zlog_debug(
+ "%s: postponing restart attempt because master %s daemon "
+ "not up [%s], or phased restart in progress",
+ dmn->name, gs.special->name,
+ state_str[gs.special->state]);
+ return;
+ }
+
+ if ((gs.phase != PHASE_NONE) || gs.numpids) {
+ if (gs.loglevel > LOG_DEBUG + 1)
+ zlog_debug(
+ "postponing phased global restart: restart already in "
+ "progress [%s], or outstanding child processes [%d]",
+ phase_str[gs.phase], gs.numpids);
+ return;
+ }
+ /* Is it too soon for a restart? */
+ {
+ struct timeval delay;
+ if (time_elapsed(&delay, &gs.special->restart.time)->tv_sec
+ < gs.special->restart.interval) {
if (gs.loglevel > LOG_DEBUG + 1)
zlog_debug(
- "postponing phased global restart: restart already in "
- "progress [%s], or outstanding child processes [%d]",
- phase_str[gs.phase], gs.numpids);
- break;
+ "postponing phased global restart: "
+ "elapsed time %ld < retry interval %ld",
+ (long)delay.tv_sec,
+ gs.special->restart.interval);
+ return;
}
- /* Is it too soon for a restart? */
- {
- struct timeval delay;
- if (time_elapsed(&delay, &gs.special->restart.time)
- ->tv_sec
- < gs.special->restart.interval) {
- if (gs.loglevel > LOG_DEBUG + 1)
- zlog_debug(
- "postponing phased global restart: "
- "elapsed time %ld < retry interval %ld",
- (long)delay.tv_sec,
- gs.special->restart.interval);
- break;
- }
- }
- run_job(&gs.restart, "restart", gs.restart_command, 0, 1);
- break;
- default:
- zlog_err("error: unknown restart mode %d", gs.mode);
- break;
}
+ run_job(&gs.restart, "restart", gs.restart_command, 0, 1);
}
static int wakeup_unresponsive(struct thread *t_wakeup)
@@ -973,10 +870,8 @@ static int wakeup_no_answer(struct thread *t_wakeup)
"%s state -> unresponsive : no response yet to ping "
"sent %ld seconds ago",
dmn->name, gs.timeout);
- if (gs.unresponsive_restart) {
- SET_WAKEUP_UNRESPONSIVE(dmn);
- try_restart(dmn);
- }
+ SET_WAKEUP_UNRESPONSIVE(dmn);
+ try_restart(dmn);
return 0;
}
@@ -1071,46 +966,41 @@ FRR_DAEMON_INFO(watchfrr, WATCHFRR,
.privs = &watchfrr_privs, )
+#define DEPRECATED_OPTIONS "aAezR:"
+
int main(int argc, char **argv)
{
int opt;
- const char *pidfile = DEFAULT_PIDFILE;
+ const char *pidfile = pidfile_default;
const char *special = "zebra";
const char *blankstr = NULL;
+ snprintf(pidfile_default, sizeof(pidfile_default), "%s/watchfrr.pid",
+ frr_vtydir);
+
frr_preinit(&watchfrr_di, argc, argv);
progname = watchfrr_di.progname;
- frr_opt_add("aAb:dek:l:i:p:r:R:S:s:t:T:z", longopts, "");
+ frr_opt_add("b:dk:l:i:p:r:S:s:t:T:" DEPRECATED_OPTIONS, longopts, "");
gs.restart.name = "all";
while ((opt = frr_getopt(argc, argv, NULL)) != EOF) {
+ if (opt && opt < 128 && strchr(DEPRECATED_OPTIONS, opt)) {
+ fprintf(stderr,
+ "The -%c option no longer exists.\n"
+ "Please refer to the watchfrr(8) man page.\n",
+ opt);
+ exit(1);
+ }
+
switch (opt) {
case 0:
break;
- case 'a':
- if ((gs.mode != MODE_MONITOR)
- && (gs.mode != MODE_SEPARATE_RESTART)) {
- fputs("Ambiguous operating mode selected.\n",
- stderr);
- frr_help_exit(1);
- }
- gs.mode = MODE_PHASED_ZEBRA_RESTART;
- break;
- case 'A':
- if ((gs.mode != MODE_MONITOR)
- && (gs.mode != MODE_SEPARATE_RESTART)) {
- fputs("Ambiguous operating mode selected.\n",
- stderr);
- frr_help_exit(1);
- }
- gs.mode = MODE_PHASED_ALL_RESTART;
- break;
case 'b':
blankstr = optarg;
break;
- case 'e':
- gs.do_ping = 0;
+ case OPTION_DRY:
+ watch_only = true;
break;
case 'k':
if (!valid_command(optarg)) {
@@ -1172,12 +1062,6 @@ int main(int argc, char **argv)
pidfile = optarg;
break;
case 'r':
- if ((gs.mode == MODE_GLOBAL_RESTART)
- || (gs.mode == MODE_SEPARATE_RESTART)) {
- fputs("Ambiguous operating mode selected.\n",
- stderr);
- frr_help_exit(1);
- }
if (!valid_command(optarg)) {
fprintf(stderr,
"Invalid restart command, must contain '%%s': %s\n",
@@ -1185,23 +1069,6 @@ int main(int argc, char **argv)
frr_help_exit(1);
}
gs.restart_command = optarg;
- if (gs.mode == MODE_MONITOR)
- gs.mode = MODE_SEPARATE_RESTART;
- break;
- case 'R':
- if (gs.mode != MODE_MONITOR) {
- fputs("Ambiguous operating mode selected.\n",
- stderr);
- frr_help_exit(1);
- }
- if (strchr(optarg, '%')) {
- fprintf(stderr,
- "Invalid restart-all arg, must not contain '%%s': %s\n",
- optarg);
- frr_help_exit(1);
- }
- gs.restart_command = optarg;
- gs.mode = MODE_GLOBAL_RESTART;
break;
case 's':
if (!valid_command(optarg)) {
@@ -1238,49 +1105,22 @@ int main(int argc, char **argv)
frr_help_exit(1);
}
} break;
- case 'z':
- gs.unresponsive_restart = 1;
- break;
default:
fputs("Invalid option.\n", stderr);
frr_help_exit(1);
}
}
- if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR)) {
- fputs("Option -z requires a -r or -R restart option.\n",
+ if (watch_only
+ && (gs.start_command || gs.stop_command || gs.restart_command)) {
+ fputs("Options -r/-s/-k are not used when --dry is active.\n",
stderr);
- frr_help_exit(1);
}
- switch (gs.mode) {
- case MODE_MONITOR:
- if (gs.restart_command || gs.start_command || gs.stop_command) {
- fprintf(stderr,
- "No kill/(re)start commands needed for %s mode.\n",
- mode_str[gs.mode]);
- frr_help_exit(1);
- }
- break;
- case MODE_GLOBAL_RESTART:
- case MODE_SEPARATE_RESTART:
- if (!gs.restart_command || gs.start_command
- || gs.stop_command) {
- fprintf(stderr,
- "No start/kill commands needed in [%s] mode.\n",
- mode_str[gs.mode]);
- frr_help_exit(1);
- }
- break;
- case MODE_PHASED_ZEBRA_RESTART:
- case MODE_PHASED_ALL_RESTART:
- if (!gs.restart_command || !gs.start_command
- || !gs.stop_command) {
- fprintf(stderr,
- "Need start, kill, and restart commands in [%s] mode.\n",
- mode_str[gs.mode]);
- frr_help_exit(1);
- }
- break;
+ if (!watch_only
+ && (!gs.restart_command || !gs.start_command || !gs.stop_command)) {
+ fprintf(stderr,
+ "Options -s (start), -k (kill), and -r (restart) are required.\n");
+ frr_help_exit(1);
}
if (blankstr) {
@@ -1343,9 +1183,7 @@ int main(int argc, char **argv)
gs.daemons = dmn;
tail = dmn;
- if (((gs.mode == MODE_PHASED_ZEBRA_RESTART)
- || (gs.mode == MODE_PHASED_ALL_RESTART))
- && !strcmp(dmn->name, special))
+ if (!strcmp(dmn->name, special))
gs.special = dmn;
}
}
@@ -1353,12 +1191,9 @@ int main(int argc, char **argv)
fputs("Must specify one or more daemons to monitor.\n", stderr);
frr_help_exit(1);
}
- if (((gs.mode == MODE_PHASED_ZEBRA_RESTART)
- || (gs.mode == MODE_PHASED_ALL_RESTART))
- && !gs.special) {
- fprintf(stderr,
- "In mode [%s], but cannot find master daemon %s\n",
- mode_str[gs.mode], special);
+ if (!watch_only && !gs.special) {
+ fprintf(stderr, "\"%s\" daemon must be in daemon list\n",
+ special);
frr_help_exit(1);
}
@@ -1383,8 +1218,9 @@ int main(int argc, char **argv)
strcpy(p, dmn->name);
p += strlen(p);
}
- zlog_notice("%s %s watching [%s], mode [%s]", progname,
- FRR_VERSION, buf, mode_str[gs.mode]);
+ zlog_notice("%s %s watching [%s]%s", progname,
+ FRR_VERSION, buf,
+ watch_only ? ", monitor mode" : "");
}
}
diff --git a/zebra/client_main.c b/zebra/client_main.c
index 17130c602e..95b9d00dc0 100644
--- a/zebra/client_main.c
+++ b/zebra/client_main.c
@@ -186,11 +186,7 @@ int main(int argc, char **argv)
/* Establish connection to zebra. */
zclient = zclient_new(master);
zclient->enable = 1;
-#ifdef HAVE_TCP_ZEBRA
- zclient->sock = zclient_socket();
-#else
- zclient->sock = zclient_socket_un(ZEBRA_SERV_PATH);
-#endif /* HAVE_TCP_ZEBRA */
+ zclient_socket_connect(zclient);
/* Open simulation file. */
fp = fopen(argv[1], "r");
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index a46657dd2e..0d08155178 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -251,6 +251,8 @@ static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
*zif_type = ZEBRA_IF_VLAN;
else if (strcmp(kind, "vxlan") == 0)
*zif_type = ZEBRA_IF_VXLAN;
+ else if (strcmp(kind, "macvlan") == 0)
+ *zif_type = ZEBRA_IF_MACVLAN;
}
// Temporary Assignments to compile on older platforms.
@@ -401,16 +403,19 @@ static int get_iflink_speed(const char *ifname)
/* use ioctl to get IP address of an interface */
sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sd < 0) {
- zlog_debug("Failure to read interface %s speed: %d %s", ifname,
- errno, safe_strerror(errno));
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Failure to read interface %s speed: %d %s",
+ ifname, errno, safe_strerror(errno));
return 0;
}
/* Get the current link state for the interface */
rc = ioctl(sd, SIOCETHTOOL, (char *)&ifdata);
if (rc < 0) {
- zlog_debug("IOCTL failure to read interface %s speed: %d %s",
- ifname, errno, safe_strerror(errno));
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "IOCTL failure to read interface %s speed: %d %s",
+ ifname, errno, safe_strerror(errno));
ecmd.speed_hi = 0;
ecmd.speed = 0;
}
diff --git a/zebra/interface.h b/zebra/interface.h
index ea72264696..970c3c5292 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -186,11 +186,12 @@ struct rtadvconf {
/* Zebra interface type - ones of interest. */
typedef enum {
- ZEBRA_IF_VXLAN, /* VxLAN interface */
- ZEBRA_IF_VRF, /* VRF device */
- ZEBRA_IF_BRIDGE, /* bridge device */
- ZEBRA_IF_VLAN, /* VLAN sub-interface */
- ZEBRA_IF_OTHER, /* Anything else */
+ ZEBRA_IF_VXLAN, /* VxLAN interface */
+ ZEBRA_IF_VRF, /* VRF device */
+ ZEBRA_IF_BRIDGE, /* bridge device */
+ ZEBRA_IF_VLAN, /* VLAN sub-interface */
+ ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/
+ ZEBRA_IF_OTHER, /* Anything else */
} zebra_iftype_t;
/* Zebra "slave" interface type */
@@ -295,6 +296,9 @@ static inline void zebra_if_set_ziftype(struct interface *ifp,
#define IS_ZEBRA_IF_VXLAN(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN)
+#define IS_ZEBRA_IF_MACVLAN(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_MACVLAN)
+
#define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_slave_type \
== ZEBRA_IF_SLAVE_BRIDGE)
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index b50f751587..1ed5eacd80 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -33,6 +33,7 @@
#include "lib/network.h"
#include "lib/stream.h"
#include "lib/zclient.h"
+#include "lib/libfrr.h"
#include "label_manager.h"
@@ -216,7 +217,8 @@ static int lm_zclient_connect(struct thread *t)
static void lm_zclient_init(char *lm_zserv_path)
{
if (lm_zserv_path)
- zclient_serv_path_set(lm_zserv_path);
+ frr_zclient_addr(&zclient_addr, &zclient_addr_len,
+ lm_zserv_path);
/* Set default values. */
zclient = zclient_new(zebrad.master);
diff --git a/zebra/main.c b/zebra/main.c
index f0bdafa353..538c2f0663 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -204,6 +204,8 @@ int main(int argc, char **argv)
char *zserv_path = NULL;
/* Socket to external label manager */
char *lblmgr_path = NULL;
+ struct sockaddr_storage dummy;
+ socklen_t dummylen;
frr_preinit(&zebra_di, argc, argv);
@@ -256,6 +258,12 @@ int main(int argc, char **argv)
break;
case 'z':
zserv_path = optarg;
+ if (!frr_zclient_addr(&dummy, &dummylen, optarg)) {
+ fprintf(stderr,
+ "Invalid zserv socket path: %s\n",
+ optarg);
+ exit(1);
+ }
break;
case 'l':
lblmgr_path = optarg;
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index c3bbf40b3f..92da5fe0ce 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -41,6 +41,7 @@
#include "zebra/debug.h"
#include "zebra/router-id.h"
#include "zebra/zebra_memory.h"
+#include "zebra/zebra_vxlan.h"
#define ZEBRA_PTM_SUPPORT
@@ -402,6 +403,8 @@ void zebra_interface_address_add_update(struct interface *ifp,
zlog_warn(
"WARNING: advertising address to clients that is not yet usable.");
+ zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 1);
+
router_id_add_address(ifc);
for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
@@ -428,6 +431,8 @@ void zebra_interface_address_delete_update(struct interface *ifp,
prefix2str(p, buf, sizeof(buf)), ifc->ifp->name);
}
+ zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0);
+
router_id_del_address(ifc);
for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index d1ab2dbb85..47cf7a3cbf 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -1321,9 +1321,9 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
default:
break;
}
- vty_out(vty, "%s",
- CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
- : "");
+ vty_out(vty, "%s", CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
+ ? " (installed)"
+ : "");
vty_out(vty, "\n");
}
@@ -2807,6 +2807,8 @@ void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
hash_free(zvrf->lsp_table);
hash_clean(zvrf->slsp_table, NULL);
hash_free(zvrf->slsp_table);
+ route_table_finish(zvrf->fec_table[AFI_IP]);
+ route_table_finish(zvrf->fec_table[AFI_IP6]);
}
/*
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index dca53bb9f3..6e2dc613df 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -107,6 +107,11 @@ struct zebra_vrf {
*/
int advertise_all_vni;
+ /*
+ * Whether we are advertising g/w macip in EVPN or not.
+ */
+ int advertise_gw_macip;
+
/* Route Installs */
uint64_t installs;
uint64_t removals;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index e260338131..f01f037ed5 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -2285,89 +2285,100 @@ DEFUN (show_vrf,
DEFUN (show_evpn_vni,
show_evpn_vni_cmd,
- "show evpn vni",
+ "show evpn vni [json]",
SHOW_STR
"EVPN\n"
- "VxLAN information\n")
+ "VxLAN information\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
+ u_char uj = use_json(argc, argv);
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_vnis(vty, zvrf);
+ zebra_vxlan_print_vnis(vty, zvrf, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_vni_vni,
show_evpn_vni_vni_cmd,
- "show evpn vni " CMD_VNI_RANGE,
+ "show evpn vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"VxLAN Network Identifier\n"
- "VNI number\n")
+ "VNI number\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
+ u_char uj = use_json(argc, argv);
vni = strtoul(argv[3]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_vni(vty, zvrf, vni);
+ zebra_vxlan_print_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni,
show_evpn_mac_vni_cmd,
- "show evpn mac vni " CMD_VNI_RANGE,
+ "show evpn mac vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
- "VNI number\n")
+ "VNI number\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
+ u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_macs_vni(vty, zvrf, vni);
+ zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all,
show_evpn_mac_vni_all_cmd,
- "show evpn mac vni all",
+ "show evpn mac vni all [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
- "All VNIs\n")
+ "All VNIs\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
+ u_char uj = use_json(argc, argv);
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_macs_all_vni(vty, zvrf);
+ zebra_vxlan_print_macs_all_vni(vty, zvrf, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all_vtep,
show_evpn_mac_vni_all_vtep_cmd,
- "show evpn mac vni all vtep A.B.C.D",
+ "show evpn mac vni all vtep A.B.C.D [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Remote VTEP\n"
- "Remote VTEP IP address\n")
+ "Remote VTEP IP address\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
struct in_addr vtep_ip;
+ u_char uj = use_json(argc, argv);
if (!inet_aton(argv[6]->arg, &vtep_ip)) {
- vty_out(vty, "%% Malformed VTEP IP address\n");
+ if (!uj)
+ vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip);
+ zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip, uj);
return CMD_SUCCESS;
}
@@ -2400,112 +2411,125 @@ DEFUN (show_evpn_mac_vni_mac,
DEFUN (show_evpn_mac_vni_vtep,
show_evpn_mac_vni_vtep_cmd,
- "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D",
+ "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D" "[json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Remote VTEP\n"
- "Remote VTEP IP address\n")
+ "Remote VTEP IP address\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct in_addr vtep_ip;
+ u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton(argv[6]->arg, &vtep_ip)) {
- vty_out(vty, "%% Malformed VTEP IP address\n");
+ if (!uj)
+ vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip);
+ zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni,
show_evpn_neigh_vni_cmd,
- "show evpn arp-cache vni " CMD_VNI_RANGE,
+ "show evpn arp-cache vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
- "VNI number\n")
+ "VNI number\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
+ u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_neigh_vni(vty, zvrf, vni);
+ zebra_vxlan_print_neigh_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_all,
show_evpn_neigh_vni_all_cmd,
- "show evpn arp-cache vni all",
+ "show evpn arp-cache vni all [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
- "All VNIs\n")
+ "All VNIs\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
+ u_char uj = use_json(argc, argv);
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_neigh_all_vni(vty, zvrf);
+ zebra_vxlan_print_neigh_all_vni(vty, zvrf, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_neigh,
show_evpn_neigh_vni_neigh_cmd,
- "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD",
+ "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Neighbor\n"
- "Neighbor address (IPv4 or IPv6 address)\n")
+ "Neighbor address (IPv4 or IPv6 address)\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct ipaddr ip;
+ u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (str2ipaddr(argv[6]->arg, &ip) != 0) {
- vty_out(vty, "%% Malformed Neighbor address\n");
+ if (!uj)
+ vty_out(vty, "%% Malformed Neighbor address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip);
+ zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_vtep,
show_evpn_neigh_vni_vtep_cmd,
- "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D",
+ "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Remote VTEP\n"
- "Remote VTEP IP address\n")
+ "Remote VTEP IP address\n"
+ JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct in_addr vtep_ip;
+ u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton(argv[6]->arg, &vtep_ip)) {
- vty_out(vty, "%% Malformed VTEP IP address\n");
+ if (!uj)
+ vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
- zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip);
+ zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS;
}
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 7d265af309..f99c16ae91 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -46,6 +46,7 @@
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_memory.h"
#include "zebra/zebra_l2.h"
+#include "lib/json.h"
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
@@ -56,24 +57,25 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
/* static function declarations */
-static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt);
+static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
- void *ctxt);
+ void **args);
static void zvni_print_mac(zebra_mac_t *mac, void *ctxt);
static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt);
static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt);
-static void zvni_print(zebra_vni_t *zvni, void *ctxt);
-static void zvni_print_hash(struct hash_backet *backet, void *ctxt);
+static void zvni_print(zebra_vni_t *zvni, void **ctxt);
+static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]);
static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr,
- struct ipaddr *ip, u_char sticky,
+ struct ipaddr *ip, u_char flags,
u_int16_t cmd);
static unsigned int neigh_hash_keymake(void *p);
static int neigh_cmp(const void *p1, const void *p2);
static void *zvni_neigh_alloc(void *p);
-static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip);
+static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
+ struct ethaddr *mac);
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n);
static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg);
static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall,
@@ -83,10 +85,10 @@ static void zvni_neigh_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip,
- struct ethaddr *macaddr);
+ struct ethaddr *macaddr, u_char flags);
static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip,
- struct ethaddr *macaddr);
+ struct ethaddr *macaddr, u_char flags);
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
static zebra_vni_t *zvni_map_svi(struct interface *ifp,
@@ -106,9 +108,9 @@ static void zvni_mac_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
int uninstall, int upd_client, u_int32_t flags);
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
- struct ethaddr *macaddr, u_char sticky);
+ struct ethaddr *macaddr, u_char flags);
static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
- struct ethaddr *macaddr, u_char sticky);
+ struct ethaddr *macaddr, u_char flags);
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid);
static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac);
@@ -131,10 +133,31 @@ static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall);
static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip);
static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip);
-
+static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
+static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
+static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
+ struct ethaddr *macaddr, struct ipaddr *ip);
+static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
+ struct ipaddr *ip);
+struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
+static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf,
+ zebra_vni_t *zvni);
+static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
+ int uninstall);
/* Private functions */
+static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf, zebra_vni_t *zvni)
+{
+ if (zvrf && zvrf->advertise_gw_macip)
+ return 1;
+
+ if (zvni && zvni->advertise_gw_macip)
+ return 1;
+
+ return 0;
+}
+
/*
* Helper function to determine maximum width of neighbor IP address for
* display - just because we're dealing with IPv6 addresses that can
@@ -159,18 +182,37 @@ static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt)
/*
* Print a specific neighbor entry.
*/
-static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt)
+static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
{
struct vty *vty;
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
- ipaddr2str(&n->ip, buf2, sizeof(buf2)), vty = (struct vty *)ctxt;
- vty_out(vty, "IP: %s\n", ipaddr2str(&n->ip, buf2, sizeof(buf2)));
- vty_out(vty, " MAC: %s", prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
- vty_out(vty, " Remote VTEP: %s", inet_ntoa(n->r_vtep_ip));
- vty_out(vty, "\n");
+ ipaddr2str(&n->ip, buf2, sizeof(buf2));
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1));
+ vty = (struct vty *)ctxt;
+ if (json == NULL) {
+ vty_out(vty, "IP: %s\n",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ vty_out(vty, " MAC: %s",
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
+ } else {
+ json_object_string_add(json, "ip", buf2);
+ json_object_string_add(json, "mac", buf1);
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ if (json == NULL) {
+ vty_out(vty, " Remote VTEP: %s",
+ inet_ntoa(n->r_vtep_ip));
+ vty_out(vty, " State: %s", IS_ZEBRA_NEIGH_ACTIVE(n)
+ ? "Active"
+ : "Inactive");
+ } else
+ json_object_string_add(json, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
+ }
+ if (json == NULL)
+ vty_out(vty, "\n");
}
/*
@@ -179,65 +221,115 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt)
static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt)
{
struct vty *vty;
+ json_object *json_vni = NULL, *json_row = NULL;
zebra_neigh_t *n;
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
struct neigh_walk_ctx *wctx = ctxt;
vty = wctx->vty;
+ json_vni = wctx->json;
n = (zebra_neigh_t *)backet->data;
if (!n)
return;
+ if (json_vni)
+ json_row = json_object_new_object();
+
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
ipaddr2str(&n->ip, buf2, sizeof(buf2));
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
&& !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) {
- vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width, buf2,
- "local", buf1);
+ if (json_vni == NULL) {
+ vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width,
+ buf2, "local", buf1);
+ } else {
+ json_object_string_add(json_row, "type", "local");
+ json_object_string_add(json_row, "mac", buf1);
+ }
wctx->count++;
} else {
if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) {
if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) {
- if (wctx->count == 0)
+ if (json_vni == NULL) {
+ if (wctx->count == 0)
+ vty_out(vty,
+ "%*s %-6s %-17s %-21s\n",
+ -wctx->addr_width,
+ "Neighbor", "Type",
+ "MAC", "Remote VTEP");
vty_out(vty, "%*s %-6s %-17s %-21s\n",
- -wctx->addr_width, "Neighbor",
- "Type", "MAC", "Remote VTEP");
+ -wctx->addr_width, buf2,
+ "remote", buf1,
+ inet_ntoa(n->r_vtep_ip));
+ } else {
+ json_object_string_add(json_row, "type",
+ "remote");
+ json_object_string_add(json_row, "mac",
+ buf1);
+ json_object_string_add(
+ json_row, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
+ }
+ wctx->count++;
+ }
+ } else {
+ if (json_vni == NULL) {
vty_out(vty, "%*s %-6s %-17s %-21s\n",
-wctx->addr_width, buf2, "remote", buf1,
inet_ntoa(n->r_vtep_ip));
- wctx->count++;
+ } else {
+ json_object_string_add(json_row, "type",
+ "remote");
+ json_object_string_add(json_row, "mac", buf1);
+ json_object_string_add(json_row, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
}
- } else {
- vty_out(vty, "%*s %-6s %-17s %-21s\n",
- -wctx->addr_width, buf2, "remote", buf1,
- inet_ntoa(n->r_vtep_ip));
wctx->count++;
}
}
+
+ if (json_vni)
+ json_object_object_add(json_vni, buf2, json_row);
}
/*
* Print neighbors for all VNI.
*/
static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
- void *ctxt)
+ void **args)
{
struct vty *vty;
+ json_object *json = NULL, *json_vni = NULL;
zebra_vni_t *zvni;
u_int32_t num_neigh;
struct neigh_walk_ctx wctx;
+ char vni_str[VNI_STR_LEN];
+
+ vty = (struct vty *)args[0];
+ json = (json_object *)args[1];
- vty = (struct vty *)ctxt;
zvni = (zebra_vni_t *)backet->data;
- if (!zvni)
+ if (!zvni) {
+ if (json)
+ vty_out(vty, "{}\n");
return;
-
+ }
num_neigh = hashcount(zvni->neigh_table);
- vty_out(vty, "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
- zvni->vni, num_neigh);
- if (!num_neigh)
+ if (json == NULL)
+ vty_out(vty,
+ "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
+ zvni->vni, num_neigh);
+ else {
+ json_vni = json_object_new_object();
+ json_object_int_add(json_vni, "numArpNd", num_neigh);
+ snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
+ }
+ if (!num_neigh) {
+ if (json)
+ json_object_object_add(json, vni_str, json_vni);
return;
+ }
/* Since we have IPv6 addresses to deal with which can vary widely in
* size, we try to be a bit more elegant in display by first computing
@@ -247,11 +339,16 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
wctx.zvni = zvni;
wctx.vty = vty;
wctx.addr_width = 15;
+ wctx.json = json_vni;
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
- vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type",
- "MAC", "Remote VTEP");
+ if (json == NULL)
+ vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
+ "Type", "MAC", "Remote VTEP");
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+
+ if (json)
+ json_object_object_add(json, vni_str, json_vni);
}
/*
@@ -260,7 +357,10 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
{
struct vty *vty;
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
char buf1[20];
+ char buf2[INET6_ADDRSTRLEN];
vty = (struct vty *)ctxt;
vty_out(vty, "MAC: %s",
@@ -278,11 +378,30 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex);
if (mac->fwd_info.local.vid)
vty_out(vty, " VLAN: %u", mac->fwd_info.local.vid);
- } else {
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
vty_out(vty, " Remote VTEP: %s",
inet_ntoa(mac->fwd_info.r_vtep_ip));
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+ vty_out(vty, " Auto Mac ");
+ }
+ vty_out(vty, " ARP ref: %u\n", mac->neigh_refcnt);
+
+ /* print all the associated neigh */
+ vty_out(vty, " Neighbors:\n");
+ if (!listcount(mac->neigh_list))
+ vty_out(vty, " No Neighbors\n");
+ else {
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
+ vty_out(vty, " %s %s\n",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+ CHECK_FLAG(n->flags, ZEBRA_MAC_LOCAL)
+ ? (IS_ZEBRA_NEIGH_ACTIVE(n)
+ ? "Active"
+ : "Inactive")
+ : "");
+ }
}
- vty_out(vty, " ARP ref: %u", mac->neigh_refcnt);
+
vty_out(vty, "\n");
}
@@ -292,16 +411,22 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
{
struct vty *vty;
+ json_object *json_mac_hdr = NULL, *json_mac = NULL;
zebra_mac_t *mac;
char buf1[20];
struct mac_walk_ctx *wctx = ctxt;
vty = wctx->vty;
+ json_mac_hdr = wctx->json;
mac = (zebra_mac_t *)backet->data;
if (!mac)
return;
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
+
+ if (json_mac_hdr)
+ json_mac = json_object_new_object();
+
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
&& !(wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)) {
struct zebra_ns *zns;
@@ -315,29 +440,70 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
if (!ifp) // unexpected
return;
vid = mac->fwd_info.local.vid;
- vty_out(vty, "%-17s %-6s %-21s", buf1, "local", ifp->name);
- if (vid)
- vty_out(vty, " %-5u", vid);
- vty_out(vty, "\n");
+ if (json_mac_hdr == NULL)
+ vty_out(vty, "%-17s %-6s %-21s", buf1, "local",
+ ifp->name);
+ else {
+ json_object_string_add(json_mac, "type", "local");
+ json_object_string_add(json_mac, "intf", ifp->name);
+ }
+ if (vid) {
+ if (json_mac_hdr == NULL)
+ vty_out(vty, " %-5u", vid);
+ else
+ json_object_int_add(json_mac, "vlan", vid);
+ }
+ if (json_mac_hdr == NULL)
+ vty_out(vty, "\n");
+ else
+ json_object_object_add(json_mac_hdr, buf1, json_mac);
wctx->count++;
- } else {
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) {
if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
&wctx->r_vtep_ip)) {
if (wctx->count == 0) {
- vty_out(vty, "\nVNI %u",
- wctx->zvni->vni);
- vty_out(vty, "%-17s %-6s %-21s %-5s",
- "MAC", "Type",
- "Intf/Remote VTEP", "VLAN");
+ if (json_mac_hdr == NULL) {
+ vty_out(vty, "\nVNI %u\n\n",
+ wctx->zvni->vni);
+ vty_out(vty,
+ "%-17s %-6s %-21s %-5s\n",
+ "MAC", "Type",
+ "Intf/Remote VTEP",
+ "VLAN");
+ }
+ }
+ if (json_mac_hdr == NULL)
+ vty_out(vty, "%-17s %-6s %-21s\n", buf1,
+ "remote",
+ inet_ntoa(mac->fwd_info
+ .r_vtep_ip));
+ else {
+ json_object_string_add(json_mac, "type",
+ "remote");
+ json_object_string_add(
+ json_mac, "remoteVtep",
+ inet_ntoa(mac->fwd_info
+ .r_vtep_ip));
+ json_object_object_add(json_mac_hdr,
+ buf1, json_mac);
}
- vty_out(vty, "%-17s %-6s %-21s", buf1, "remote",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
wctx->count++;
}
} else {
- vty_out(vty, "%-17s %-6s %-21s", buf1, "remote",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
+ if (json_mac_hdr == NULL)
+ vty_out(vty, "%-17s %-6s %-21s\n", buf1,
+ "remote",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ else {
+ json_object_string_add(json_mac, "type",
+ "remote");
+ json_object_string_add(
+ json_mac, "remoteVtep",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ json_object_object_add(json_mac_hdr, buf1,
+ json_mac);
+ }
wctx->count++;
}
}
@@ -349,15 +515,22 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt)
{
struct vty *vty;
+ json_object *json = NULL, *json_vni = NULL;
+ json_object *json_mac = NULL;
zebra_vni_t *zvni;
u_int32_t num_macs;
struct mac_walk_ctx *wctx = ctxt;
+ char vni_str[VNI_STR_LEN];
vty = (struct vty *)wctx->vty;
+ json = (struct json_object *)wctx->json;
zvni = (zebra_vni_t *)backet->data;
- if (!zvni)
+ if (!zvni) {
+ if (json)
+ vty_out(vty, "{}\n");
return;
+ }
wctx->zvni = zvni;
/*We are iterating over a new VNI, set the count to 0*/
@@ -366,59 +539,119 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt)
num_macs = hashcount(zvni->mac_table);
if (!num_macs)
return;
- if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
- vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
- zvni->vni, num_macs);
- vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
- "Intf/Remote VTEP", "VLAN");
+
+ if (json) {
+ json_vni = json_object_new_object();
+ json_mac = json_object_new_object();
+ snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
}
+ if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
+ if (json == NULL) {
+ vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
+ zvni->vni, num_macs);
+ vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
+ "Intf/Remote VTEP", "VLAN");
+ } else
+ json_object_int_add(json_vni, "numMacs", num_macs);
+ }
+ /* assign per-vni to wctx->json object to fill macs
+ * under the vni. Re-assign primary json object to fill
+ * next vni information.
+ */
+ wctx->json = json_mac;
hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx);
+ wctx->json = json;
+ if (json) {
+ if (wctx->count)
+ json_object_object_add(json_vni, "macs", json_mac);
+ json_object_object_add(json, vni_str, json_vni);
+ }
}
/*
* Print a specific VNI entry.
*/
-static void zvni_print(zebra_vni_t *zvni, void *ctxt)
+static void zvni_print(zebra_vni_t *zvni, void **ctxt)
{
struct vty *vty;
zebra_vtep_t *zvtep;
u_int32_t num_macs;
u_int32_t num_neigh;
+ json_object *json = NULL;
+ json_object *json_vtep_list = NULL;
+ json_object *json_ip_str = NULL;
- vty = (struct vty *)ctxt;
+ vty = ctxt[0];
+ json = ctxt[1];
+
+ if (json == NULL)
+ vty_out(vty, "VNI: %u\n", zvni->vni);
+ else
+ json_object_int_add(json, "vni", zvni->vni);
- vty_out(vty, "VNI: %u\n", zvni->vni);
if (!zvni->vxlan_if) { // unexpected
- vty_out(vty, " VxLAN interface: unknown\n");
+ if (json == NULL)
+ vty_out(vty, " VxLAN interface: unknown\n");
return;
}
- vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n",
- zvni->vxlan_if->name, zvni->vxlan_if->ifindex,
- inet_ntoa(zvni->local_vtep_ip));
-
+ num_macs = hashcount(zvni->mac_table);
+ num_neigh = hashcount(zvni->neigh_table);
+ if (json == NULL)
+ vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n",
+ zvni->vxlan_if->name, zvni->vxlan_if->ifindex,
+ inet_ntoa(zvni->local_vtep_ip));
+ else {
+ json_object_string_add(json, "vxlanInterface",
+ zvni->vxlan_if->name);
+ json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
+ json_object_string_add(json, "vtepIp",
+ inet_ntoa(zvni->local_vtep_ip));
+ json_object_string_add(json, "advertiseGatewayMacip",
+ zvni->advertise_gw_macip ? "Yes" : "No");
+ json_object_int_add(json, "numMacs", num_macs);
+ json_object_int_add(json, "numArpNd", num_neigh);
+ }
if (!zvni->vteps) {
- vty_out(vty, " No remote VTEPs known for this VNI\n");
+ if (json == NULL)
+ vty_out(vty, " No remote VTEPs known for this VNI\n");
} else {
- vty_out(vty, " Remote VTEPs for this VNI:\n");
- for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next)
- vty_out(vty, " %s\n", inet_ntoa(zvtep->vtep_ip));
+ if (json == NULL)
+ vty_out(vty, " Remote VTEPs for this VNI:\n");
+ else
+ json_vtep_list = json_object_new_array();
+ for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
+ if (json == NULL)
+ vty_out(vty, " %s\n",
+ inet_ntoa(zvtep->vtep_ip));
+ else {
+ json_ip_str = json_object_new_string(
+ inet_ntoa(zvtep->vtep_ip));
+ json_object_array_add(json_vtep_list,
+ json_ip_str);
+ }
+ }
+ if (json)
+ json_object_object_add(json, "numRemoteVteps",
+ json_vtep_list);
+ }
+ if (json == NULL) {
+ vty_out(vty,
+ " Number of MACs (local and remote) known for this VNI: %u\n",
+ num_macs);
+ vty_out(vty,
+ " Number of ARPs (IPv4 and IPv6, local and remote) "
+ "known for this VNI: %u\n",
+ num_neigh);
+ vty_out(vty, " Advertise-gw-macip: %s\n",
+ zvni->advertise_gw_macip ? "Yes" : "No");
}
- num_macs = hashcount(zvni->mac_table);
- vty_out(vty,
- " Number of MACs (local and remote) known for this VNI: %u\n",
- num_macs);
- num_neigh = hashcount(zvni->neigh_table);
- vty_out(vty,
- " Number of ARPs (IPv4 and IPv6, local and remote) "
- "known for this VNI: %u",
- num_neigh);
}
/*
* Print a VNI hash entry - called for display of all VNIs.
*/
-static void zvni_print_hash(struct hash_backet *backet, void *ctxt)
+static void zvni_print_hash(struct hash_backet *backet, void *ctxt[])
{
struct vty *vty;
zebra_vni_t *zvni;
@@ -426,8 +659,14 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt)
u_int32_t num_vteps = 0;
u_int32_t num_macs = 0;
u_int32_t num_neigh = 0;
+ json_object *json = NULL;
+ json_object *json_vni = NULL;
+ json_object *json_ip_str = NULL;
+ json_object *json_vtep_list = NULL;
+
+ vty = ctxt[0];
+ json = ctxt[1];
- vty = (struct vty *)ctxt;
zvni = (zebra_vni_t *)backet->data;
if (!zvni)
return;
@@ -440,9 +679,36 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt)
num_macs = hashcount(zvni->mac_table);
num_neigh = hashcount(zvni->neigh_table);
- vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni,
- zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
- inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh, num_vteps);
+ if (json == NULL)
+ vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni,
+ zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
+ inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
+ num_vteps);
+ else {
+ char vni_str[VNI_STR_LEN];
+ snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
+ json_vni = json_object_new_object();
+ json_object_string_add(json_vni, "vxlanIf",
+ zvni->vxlan_if ? zvni->vxlan_if->name
+ : "unknown");
+ json_object_string_add(json_vni, "vtepIp",
+ inet_ntoa(zvni->local_vtep_ip));
+ json_object_int_add(json_vni, "numMacs", num_macs);
+ json_object_int_add(json_vni, "numArpNd", num_neigh);
+ json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
+ if (num_vteps) {
+ json_vtep_list = json_object_new_array();
+ for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
+ json_ip_str = json_object_new_string(
+ inet_ntoa(zvtep->vtep_ip));
+ json_object_array_add(json_vtep_list,
+ json_ip_str);
+ }
+ json_object_object_add(json_vni, "remoteVteps",
+ json_vtep_list);
+ }
+ json_object_object_add(json, vni_str, json_vni);
+ }
}
/*
@@ -450,7 +716,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt)
*/
static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr,
- struct ipaddr *ip, u_char sticky,
+ struct ipaddr *ip, u_char flags,
u_int16_t cmd)
{
struct zserv *client;
@@ -483,19 +749,18 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
} else
stream_putl(s, 0); /* Just MAC. */
- stream_putc(s, sticky); /* Sticky MAC? */
+ stream_putc(s, flags); /* sticky mac/gateway mac */
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("%u:Send MACIP %s %sMAC %s IP %s VNI %u to %s",
- zvrf_id(zvrf),
- (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
- sticky ? "sticky " : "",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ip, buf2, sizeof(buf2)), vni,
- zebra_route_string(client->proto));
+ zlog_debug(
+ "%u:Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s",
+ zvrf_id(zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+ flags, prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), vni,
+ zebra_route_string(client->proto));
if (cmd == ZEBRA_MACIP_ADD)
client->macipadd_cnt++;
@@ -554,16 +819,26 @@ static void *zvni_neigh_alloc(void *p)
/*
* Add neighbor entry.
*/
-static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip)
+static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
+ struct ethaddr *mac)
{
zebra_neigh_t tmp_n;
zebra_neigh_t *n = NULL;
+ zebra_mac_t *zmac = NULL;
memset(&tmp_n, 0, sizeof(zebra_neigh_t));
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc);
assert(n);
+ memcpy(&n->emac, mac, ETH_ALEN);
+ n->state = ZEBRA_NEIGH_INACTIVE;
+
+ /* Associate the neigh to mac */
+ zmac = zvni_mac_lookup(zvni, mac);
+ if (zmac)
+ listnode_add_sort(zmac->neigh_list, n);
+
return n;
}
@@ -573,6 +848,11 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip)
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
{
zebra_neigh_t *tmp_n;
+ zebra_mac_t *zmac = NULL;
+
+ zmac = zvni_mac_lookup(zvni, &n->emac);
+ if (zmac)
+ listnode_delete(zmac->neigh_list, n);
/* Free the VNI hash entry and allocated memory. */
tmp_n = hash_release(zvni->neigh_table, n);
@@ -597,8 +877,9 @@ static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg)
&& (n->flags & ZEBRA_NEIGH_REMOTE)
&& IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
- zvni_neigh_send_del_to_client(
- wctx->zvrf, wctx->zvni->vni, &n->ip, &n->emac);
+ zvni_neigh_send_del_to_client(wctx->zvrf,
+ wctx->zvni->vni, &n->ip,
+ &n->emac, 0);
if (wctx->uninstall)
zvni_neigh_uninstall(wctx->zvni, n);
@@ -671,14 +952,154 @@ static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
return n;
}
+/* Process all neigh associated to a mac upon local mac add event */
+static void zvni_process_neigh_on_local_mac_add(struct zebra_vrf *zvrf,
+ zebra_vni_t *zvni,
+ zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ /* MAC is learnt locally, program all inactive neigh
+ * pointing to this mac */
+ if (IS_ZEBRA_NEIGH_INACTIVE(n)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: neigh %s (MAC %s) on VNI %u is now ACTIVE",
+ zvrf_id(zvrf),
+ ipaddr2str(&n->ip, buf2,
+ sizeof(buf2)),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ zvni->vni);
+
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+ zvni_neigh_send_add_to_client(
+ zvrf, zvni->vni, &n->ip, &n->emac, 0);
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: neigh %s (MAC %s) on VNI %u should NOT be ACTIVE",
+ zvrf_id(zvrf),
+ ipaddr2str(&n->ip, buf2,
+ sizeof(buf2)),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ zvni->vni);
+ }
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ /* TODO: assume the neigh has moved too ?? */
+ }
+ }
+}
+
+/* Process all neigh associated to a mac upon local mac del event */
+static void zvni_process_neigh_on_local_mac_del(struct zebra_vrf *zvrf,
+ zebra_vni_t *zvni,
+ zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: neigh %s (MAC %s) on VNI %u is now INACTIVE",
+ zvrf_id(zvrf),
+ ipaddr2str(&n->ip, buf2,
+ sizeof(buf2)),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ zvni->vni);
+
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ zvni_neigh_send_del_to_client(
+ zvrf, zvni->vni, &n->ip, &n->emac, 0);
+ }
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_err(
+ "%u: local MAC %s getting deleted on VNI %u has remote neigh %s",
+ zvrf_id(zvrf),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ zvni->vni,
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ }
+ }
+}
+
+/* process all neigh associated to a mac entry upon remote mac add */
+static void zvni_process_neigh_on_remote_mac_add(struct zebra_vrf *zvrf,
+ zebra_vni_t *zvni,
+ zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: neigh %s (MAC %s) on VNI %u INACTIVE",
+ zvrf_id(zvrf),
+ ipaddr2str(&n->ip, buf2,
+ sizeof(buf2)),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ zvni->vni);
+
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ zvni_neigh_send_del_to_client(
+ zvrf, zvni->vni, &n->ip, &n->emac, 0);
+ }
+ }
+ }
+}
+
+/* process all neigh associated to mac entry upon remote mac del */
+static void zvni_process_neigh_on_remote_mac_del(struct zebra_vrf *zvrf,
+ zebra_vni_t *zvni,
+ zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_err(
+ "%u: remote MAC %s getting deleted on VNI %u has local neigh %s",
+ zvrf_id(zvrf),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ zvni->vni,
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ }
+ }
+}
+
/*
* Inform BGP about local neighbor addition.
*/
static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip,
- struct ethaddr *macaddr)
+ struct ethaddr *macaddr, u_char flags)
{
- return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, 0,
+ return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags,
ZEBRA_MACIP_ADD);
}
@@ -687,9 +1108,9 @@ static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
*/
static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip,
- struct ethaddr *macaddr)
+ struct ethaddr *macaddr, u_char flags)
{
- return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, 0,
+ return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags,
ZEBRA_MACIP_DEL);
}
@@ -770,6 +1191,309 @@ static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt)
zvni_neigh_install(wctx->zvni, n);
}
+/* Get the VRR interface for SVI if any */
+struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp)
+{
+ struct zebra_vrf *zvrf = NULL;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif = NULL;
+ struct listnode *node;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
+ assert(zvrf);
+
+ for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) {
+ zif = tmp_if->info;
+ if (!zif)
+ continue;
+
+ if (!IS_ZEBRA_IF_MACVLAN(tmp_if))
+ continue;
+
+ if (zif->link == ifp)
+ return tmp_if;
+ }
+
+ return NULL;
+}
+
+static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
+{
+ struct zebra_vrf *zvrf = NULL;
+ struct listnode *cnode = NULL, *cnnode = NULL;
+ struct connected *c = NULL;
+ struct ethaddr macaddr;
+
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
+ return -1;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+ struct ipaddr ip;
+
+ memset(&ip, 0, sizeof(struct ipaddr));
+ if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+ continue;
+
+ if (c->address->family == AF_INET) {
+ ip.ipa_type = IPADDR_V4;
+ memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
+ sizeof(struct in_addr));
+ } else if (c->address->family == AF_INET6) {
+ ip.ipa_type = IPADDR_V6;
+ memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
+ sizeof(struct in6_addr));
+ } else {
+ continue;
+ }
+
+ zvni_gw_macip_del(ifp, zvni, &ip);
+ }
+
+ return 0;
+}
+
+static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
+{
+ struct zebra_vrf *zvrf = NULL;
+ struct listnode *cnode = NULL, *cnnode = NULL;
+ struct connected *c = NULL;
+ struct ethaddr macaddr;
+
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
+ return -1;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+ struct ipaddr ip;
+
+ memset(&ip, 0, sizeof(struct ipaddr));
+ if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+ continue;
+
+ if (c->address->family == AF_INET) {
+ ip.ipa_type = IPADDR_V4;
+ memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
+ sizeof(struct in_addr));
+ } else if (c->address->family == AF_INET6) {
+ ip.ipa_type = IPADDR_V6;
+ memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
+ sizeof(struct in6_addr));
+ } else {
+ continue;
+ }
+
+ zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
+ }
+
+ return 0;
+}
+
+/*
+ * zvni_gw_macip_add_to_client
+ */
+static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
+ struct ethaddr *macaddr, struct ipaddr *ip)
+{
+ struct zebra_vrf *zvrf = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *mac = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
+ return -1;
+
+ zif = zvni->vxlan_if->info;
+ if (!zif)
+ return -1;
+
+ vxl = &zif->l2info.vxl;
+
+ mac = zvni_mac_lookup(zvni, macaddr);
+ if (!mac) {
+ mac = zvni_mac_add(zvni, macaddr);
+ if (!mac) {
+ zlog_err("%u:Failed to add MAC %s intf %s(%u) VID %u",
+ ifp->vrf_id,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vxl->access_vlan);
+ return -1;
+ }
+ }
+
+ /* Set "local" forwarding info. */
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vxl->access_vlan;
+
+ n = zvni_neigh_lookup(zvni, ip);
+ if (!n) {
+ n = zvni_neigh_add(zvni, ip, macaddr);
+ if (!n) {
+ zlog_err(
+ "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
+ ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, NULL,
+ ETHER_ADDR_STRLEN),
+ ifp->name, ifp->ifindex, zvni->vni);
+ return -1;
+ }
+ }
+
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+ n->ifindex = ifp->ifindex;
+
+ /* We have a neigh associated to mac increment the refcnt*/
+ mac->neigh_refcnt++;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP",
+ ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
+ prefix_mac2str(macaddr, NULL, ETHER_ADDR_STRLEN),
+ ipaddr2str(ip, buf2, sizeof(buf2)));
+
+ zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr,
+ ZEBRA_MAC_TYPE_GW);
+
+ return 0;
+}
+
+/*
+ * zvni_gw_macip_del_from_client
+ */
+static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
+ struct ipaddr *ip)
+{
+ struct zebra_vrf *zvrf = NULL;
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *mac = NULL;
+ char buf2[INET6_ADDRSTRLEN];
+
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
+ return -1;
+
+ /* If the neigh entry is not present nothing to do*/
+ n = zvni_neigh_lookup(zvni, ip);
+ if (!n)
+ return 0;
+
+ /* mac entry should be present */
+ mac = zvni_mac_lookup(zvni, &n->emac);
+ if (!mac)
+ zlog_err("%u: MAC %s doesnt exsists for neigh %s on VNI %u",
+ ifp->vrf_id,
+ prefix_mac2str(&n->emac, NULL, ETHER_ADDR_STRLEN),
+ ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+
+ /* If the entry is not local nothing to do*/
+ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
+ ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
+ prefix_mac2str(&(n->emac), NULL, ETHER_ADDR_STRLEN),
+ ipaddr2str(ip, buf2, sizeof(buf2)));
+
+ /* Remove neighbor from BGP. */
+ zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac,
+ ZEBRA_MAC_TYPE_GW);
+
+ /* Delete this neighbor entry. */
+ zvni_neigh_del(zvni, n);
+
+ /* see if the mac needs to be deleted as well*/
+ zvni_deref_ip2mac(zvni, mac, 0);
+
+ return 0;
+}
+
+static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet,
+ void *zvrf)
+{
+ zebra_vni_t *zvni = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *vrr_if = NULL;
+
+ /* Add primary SVI MAC*/
+ zvni = (zebra_vni_t *)backet->data;
+ if (!zvni)
+ return;
+
+ zif = zvni->vxlan_if->info;
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
+ zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ /* Del primary MAC-IP */
+ zvni_del_macip_for_intf(vlan_if, zvni);
+
+ /* Del VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_del_macip_for_intf(vrr_if, zvni);
+
+ return;
+}
+
+static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
+ void *zvrf)
+{
+ zebra_vni_t *zvni = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *vrr_if = NULL;
+
+ zvni = (zebra_vni_t *)backet->data;
+ if (!zvni)
+ return;
+
+ if (!advertise_gw_macip_enabled(zvrf, zvni))
+ return;
+
+ zif = zvni->vxlan_if->info;
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
+ zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ if (!advertise_gw_macip_enabled(zvrf, zvni))
+ return;
+
+ /* Add primary SVI MAC-IP */
+ zvni_add_macip_for_intf(vlan_if, zvni);
+
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_add_macip_for_intf(vrr_if, zvni);
+
+ return;
+}
+
/*
* Make hash key for MAC.
*/
@@ -827,6 +1551,9 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
assert(mac);
+ mac->neigh_list = list_new();
+ mac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp;
+
return mac;
}
@@ -837,6 +1564,8 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
{
zebra_mac_t *tmp_mac;
+ list_delete(mac->neigh_list);
+
/* Free the VNI hash entry and allocated memory. */
tmp_mac = hash_release(zvni->mac_table, mac);
if (tmp_mac)
@@ -864,8 +1593,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1
: 0;
- zvni_mac_send_del_to_client(wctx->zvrf, wctx->zvni->vni,
- &mac->macaddr, sticky);
+ zvni_mac_send_del_to_client(
+ wctx->zvrf, wctx->zvni->vni, &mac->macaddr,
+ (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
}
if (wctx->uninstall)
@@ -941,9 +1671,9 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
* Inform BGP about local MAC addition.
*/
static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
- struct ethaddr *macaddr, u_char sticky)
+ struct ethaddr *macaddr, u_char flags)
{
- return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, sticky,
+ return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags,
ZEBRA_MACIP_ADD);
}
@@ -951,9 +1681,9 @@ static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
* Inform BGP about local MAC deletion.
*/
static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
- struct ethaddr *macaddr, u_char sticky)
+ struct ethaddr *macaddr, u_char flags)
{
- return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, sticky,
+ return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags,
ZEBRA_MACIP_DEL);
}
@@ -1234,6 +1964,7 @@ static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
struct zebra_if *zif;
struct interface *vlan_if;
struct zebra_l2info_vxlan *vxl;
+ struct interface *vrr_if;
zif = ifp->info;
vxl = &zif->l2info.vxl;
@@ -1247,8 +1978,20 @@ static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
macfdb_read_for_bridge(zvrf->zns, ifp, zif->brslave_info.br_if);
vlan_if = zvni_map_to_svi(zvrf, vxl->access_vlan,
zif->brslave_info.br_if);
- if (vlan_if)
+ if (vlan_if) {
+
+ if (advertise_gw_macip_enabled(zvrf, zvni)) {
+ /* Add SVI MAC-IP */
+ zvni_add_macip_for_intf(vlan_if, zvni);
+
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_add_macip_for_intf(vrr_if, zvni);
+ }
+
neigh_read_for_vlan(zvrf->zns, vlan_if);
+ }
}
/*
@@ -1605,23 +2348,30 @@ static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
* Display Neighbors for a VNI (VTY command handler).
*/
void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni)
+ vni_t vni, u_char use_json)
{
zebra_vni_t *zvni;
u_int32_t num_neigh;
struct neigh_walk_ctx wctx;
+ json_object *json = NULL;
if (!EVPN_ENABLED(zvrf))
return;
zvni = zvni_lookup(zvrf, vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
num_neigh = hashcount(zvni->neigh_table);
if (!num_neigh)
return;
+ if (use_json)
+ json = json_object_new_object();
+
/* Since we have IPv6 addresses to deal with which can vary widely in
* size, we try to be a bit more elegant in display by first computing
* the maximum width.
@@ -1630,25 +2380,52 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
wctx.zvni = zvni;
wctx.vty = vty;
wctx.addr_width = 15;
+ wctx.json = json;
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
- vty_out(vty,
- "Number of ARPs (local and remote) known for this VNI: %u\n",
- num_neigh);
- vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type",
- "MAC", "Remote VTEP");
+ if (!use_json) {
+ vty_out(vty,
+ "Number of ARPs (local and remote) known for this VNI: %u\n",
+ num_neigh);
+ vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
+ "Type", "MAC", "Remote VTEP");
+ } else
+ json_object_int_add(json, "numArpNd", num_neigh);
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
* Display neighbors across all VNIs (VTY command handler).
*/
-void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf)
+void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
{
+ json_object *json = NULL;
+ void *args[2];
+
if (!EVPN_ENABLED(zvrf))
return;
- hash_iterate(zvrf->vni_table, zvni_print_neigh_hash_all_vni, vty);
+
+ if (use_json)
+ json = json_object_new_object();
+
+ args[0] = vty;
+ args[1] = json;
+ hash_iterate(zvrf->vni_table,
+ (void (*)(struct hash_backet *,
+ void *))zvni_print_neigh_hash_all_vni,
+ args);
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
@@ -1656,26 +2433,40 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf)
*/
void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni,
- struct ipaddr *ip)
+ struct ipaddr *ip, u_char use_json)
{
zebra_vni_t *zvni;
zebra_neigh_t *n;
+ json_object *json = NULL;
if (!EVPN_ENABLED(zvrf))
return;
zvni = zvni_lookup(zvrf, vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
n = zvni_neigh_lookup(zvni, ip);
if (!n) {
- vty_out(vty, "%% Requested neighbor does not exist in VNI %u\n",
- vni);
+ if (!use_json)
+ vty_out(vty,
+ "%% Requested neighbor does not exist in VNI %u\n",
+ vni);
return;
}
+ if (use_json)
+ json = json_object_new_object();
- zvni_print_neigh(n, vty);
+ zvni_print_neigh(n, vty, 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);
+ }
}
/*
@@ -1683,17 +2474,22 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
* By definition, these are remote neighbors.
*/
void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni, struct in_addr vtep_ip)
+ vni_t vni, struct in_addr vtep_ip,
+ u_char use_json)
{
zebra_vni_t *zvni;
u_int32_t num_neigh;
struct neigh_walk_ctx wctx;
+ json_object *json = NULL;
if (!EVPN_ENABLED(zvrf))
return;
zvni = zvni_lookup(zvrf, vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
num_neigh = hashcount(zvni->neigh_table);
@@ -1705,56 +2501,98 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
wctx.vty = vty;
wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP;
wctx.r_vtep_ip = vtep_ip;
-
+ wctx.json = json;
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
* Display MACs for a VNI (VTY command handler).
*/
void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni)
+ vni_t vni, u_char use_json)
{
zebra_vni_t *zvni;
u_int32_t num_macs;
struct mac_walk_ctx wctx;
+ json_object *json = NULL;
+ json_object *json_mac = NULL;
if (!EVPN_ENABLED(zvrf))
return;
zvni = zvni_lookup(zvrf, vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
num_macs = hashcount(zvni->mac_table);
if (!num_macs)
return;
+ if (use_json) {
+ json = json_object_new_object();
+ json_mac = json_object_new_object();
+ }
+
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
wctx.zvni = zvni;
wctx.vty = vty;
+ wctx.json = json_mac;
- vty_out(vty,
- "Number of MACs (local and remote) known for this VNI: %u\n",
- num_macs);
- vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
- "Intf/Remote VTEP", "VLAN");
+ if (!use_json) {
+ vty_out(vty,
+ "Number of MACs (local and remote) known for this VNI: %u\n",
+ num_macs);
+ vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
+ "Intf/Remote VTEP", "VLAN");
+ } else
+ json_object_int_add(json, "numMacs", num_macs);
hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
+
+ if (use_json) {
+ json_object_object_add(json, "macs", json_mac);
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
* Display MACs for all VNIs (VTY command handler).
*/
-void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf)
+void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
{
struct mac_walk_ctx wctx;
+ json_object *json = NULL;
- if (!EVPN_ENABLED(zvrf))
+ if (!EVPN_ENABLED(zvrf)) {
+ if (use_json)
+ vty_out(vty, "{}\n");
return;
+ }
+ if (use_json)
+ json = json_object_new_object();
+
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
wctx.vty = vty;
+ wctx.json = json;
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
@@ -1762,17 +2600,30 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf)
*/
void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf,
- struct in_addr vtep_ip)
+ struct in_addr vtep_ip,
+ u_char use_json)
{
struct mac_walk_ctx wctx;
+ json_object *json = NULL;
if (!EVPN_ENABLED(zvrf))
return;
+
+ if (use_json)
+ json = json_object_new_object();
+
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
wctx.vty = vty;
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
wctx.r_vtep_ip = vtep_ip;
+ wctx.json = json;
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
@@ -1805,64 +2656,128 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
* Display MACs for a VNI from specific VTEP (VTY command handler).
*/
void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni, struct in_addr vtep_ip)
+ vni_t vni, struct in_addr vtep_ip,
+ u_char use_json)
{
zebra_vni_t *zvni;
u_int32_t num_macs;
struct mac_walk_ctx wctx;
+ json_object *json = NULL;
+ json_object *json_mac = NULL;
if (!EVPN_ENABLED(zvrf))
return;
zvni = zvni_lookup(zvrf, vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
num_macs = hashcount(zvni->mac_table);
if (!num_macs)
return;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_mac = json_object_new_object();
+ }
+
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
wctx.zvni = zvni;
wctx.vty = vty;
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
wctx.r_vtep_ip = vtep_ip;
+ wctx.json = json_mac;
hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
+
+ if (use_json) {
+ json_object_int_add(json, "numMacs", wctx.count);
+ if (wctx.count)
+ json_object_object_add(json, "macs", json_mac);
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
* Display VNI information (VTY command handler).
*/
-void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni)
+void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
+ u_char use_json)
{
zebra_vni_t *zvni;
+ json_object *json = NULL;
+ void *args[2];
if (!EVPN_ENABLED(zvrf))
return;
zvni = zvni_lookup(zvrf, vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- zvni_print(zvni, (void *)vty);
+ if (use_json)
+ json = json_object_new_object();
+ args[0] = vty;
+ args[1] = json;
+ zvni_print(zvni, (void *)args);
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
* Display VNI hash table (VTY command handler).
*/
-void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf)
+void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
{
u_int32_t num_vnis;
+ json_object *json = NULL;
+ void *args[2];
if (!EVPN_ENABLED(zvrf))
return;
num_vnis = hashcount(zvrf->vni_table);
- if (!num_vnis)
+ if (!num_vnis) {
+ if (use_json)
+ vty_out(vty, "{}\n");
return;
- vty_out(vty, "Number of VNIs: %u\n", num_vnis);
- vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", "VxLAN IF",
- "VTEP IP", "# MACs", "# ARPs", "# Remote VTEPs");
- hash_iterate(zvrf->vni_table, zvni_print_hash, vty);
+ }
+ if (use_json) {
+ json = json_object_new_object();
+ json_object_string_add(json, "advertiseGatewayMacip",
+ zvrf->advertise_gw_macip ? "Yes" : "No");
+ json_object_int_add(json, "numVnis", num_vnis);
+ } else {
+ vty_out(vty, "Advertise gateway mac-ip: %s\n",
+ zvrf->advertise_gw_macip ? "Yes" : "No");
+ vty_out(vty, "Number of VNIs: %u\n", num_vnis);
+ vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI",
+ "VxLAN IF", "VTEP IP", "# MACs", "# ARPs",
+ "# Remote VTEPs");
+ }
+ args[0] = vty;
+ args[1] = json;
+
+ hash_iterate(zvrf->vni_table,
+ (void (*)(struct hash_backet *, void *))zvni_print_hash,
+ args);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
}
/*
@@ -1878,6 +2793,8 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
zebra_neigh_t *n;
struct zebra_vrf *zvrf;
char buf[INET6_ADDRSTRLEN];
+ char buf2[ETHER_ADDR_STRLEN];
+ zebra_mac_t *zmac;
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
@@ -1902,6 +2819,18 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
if (!n)
return 0;
+ zmac = zvni_mac_lookup(zvni, &n->emac);
+ if (!zmac) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_err(
+ "%u: trying to del a neigh %s without a mac %s on VNI %u",
+ ifp->vrf_id, ipaddr2str(ip, buf, sizeof(buf)),
+ prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
+ zvni->vni);
+
+ return 0;
+ }
+
/* If it is a remote entry, the kernel has aged this out or someone has
* deleted it, it needs to be re-installed as Quagga is the owner.
*/
@@ -1915,11 +2844,18 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
assert(zvrf);
/* Remove neighbor from BGP. */
- zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac);
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac,
+ 0);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
+ /* see if the AUTO mac needs to be deleted */
+ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
+ || !listcount(zmac->neigh_list))
+ zvni_mac_del(zvni, zmac);
+
return 0;
}
@@ -1936,6 +2872,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
zebra_vni_t *zvni;
zebra_neigh_t *n;
struct zebra_vrf *zvrf;
+ zebra_mac_t *zmac;
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
int send_upd = 1, send_del = 0;
@@ -1960,6 +2897,30 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
ifp->ifindex, state, ext_learned ? "ext-learned " : "",
zvni->vni);
+ /* create a dummy MAC if the MAC is not already present */
+ zmac = zvni_mac_lookup(zvni, macaddr);
+ if (!zmac) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: AUTO MAC %s created for neigh %s on VNI %u",
+ ifp->vrf_id,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+
+ zmac = zvni_mac_add(zvni, macaddr);
+ if (!zmac) {
+ zlog_warn("%u:Failed to add MAC %s VNI %u",
+ zvrf_id(zvrf),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+ return -1;
+ }
+
+ memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
+ memset(&zmac->flags, 0, sizeof(u_int32_t));
+ SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+ }
+
/* If same entry already exists, it might be a change or it might be a
* move from remote to local.
*/
@@ -1995,7 +2956,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
n->r_vtep_ip.s_addr = 0;
}
} else {
- n = zvni_neigh_add(zvni, ip);
+ n = zvni_neigh_add(zvni, ip, macaddr);
if (!n) {
zlog_err(
"%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
@@ -2008,18 +2969,39 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
/* Issue delete for older info, if needed. */
if (send_del)
- zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip,
- &n->emac);
+ zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac,
+ 0);
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- memcpy(&n->emac, macaddr, ETH_ALEN);
n->ifindex = ifp->ifindex;
+ /* Before we program this in BGP, we need to check if MAC is locally
+ * learnt as well */
+ if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: Skipping neigh %s add to client as MAC %s is not local on VNI %u",
+ ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+
+ return 0;
+ }
+
/* Inform BGP if required. */
- if (send_upd)
+ if (send_upd) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u: neigh %s (MAC %s) is now ACTIVE on VNI %u",
+ ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
+
+ ZEBRA_NEIGH_SET_ACTIVE(n);
return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip,
- macaddr);
+ macaddr, 0);
+ }
return 0;
}
@@ -2147,6 +3129,9 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length,
}
} else {
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ zvni_process_neigh_on_remote_mac_del(zvrf, zvni,
+ mac);
+
if (!mac->neigh_refcnt) {
zvni_mac_uninstall(zvni, mac, 0);
zvni_mac_del(zvni, mac);
@@ -2303,6 +3288,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
else
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ zvni_process_neigh_on_remote_mac_add(zvrf, zvni, mac);
+
/* Install the entry. */
zvni_mac_install(zvni, mac);
}
@@ -2326,7 +3313,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
if (update_neigh) {
if (!n) {
- n = zvni_neigh_add(zvni, &ip);
+ n = zvni_neigh_add(zvni, &ip, &macaddr);
if (!n) {
zlog_warn(
"%u:Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
@@ -2349,12 +3336,12 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
if (old_mac)
zvni_deref_ip2mac(zvni, old_mac, 1);
mac->neigh_refcnt++;
+ memcpy(&n->emac, &macaddr, ETH_ALEN);
}
/* Set "remote" forwarding info. */
UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
/* TODO: Handle MAC change. */
- memcpy(&n->emac, &macaddr, ETH_ALEN);
n->r_vtep_ip = vtep_ip;
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
@@ -2419,10 +3406,19 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
/* Remove MAC from BGP. */
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
- zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, sticky);
+ zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr,
+ (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
- /* Delete this MAC entry. */
- zvni_mac_del(zvni, mac);
+ /*
+ * If there are no neigh associated with the mac delete the mac
+ * else mark it as AUTO for forward reference
+ */
+ if (!listcount(mac->neigh_list)) {
+ zvni_mac_del(zvni, mac);
+ } else {
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ }
return 0;
}
@@ -2526,10 +3522,22 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
/* Remove MAC from BGP. */
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
- zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, sticky);
+ zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr,
+ (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
- /* Delete this MAC entry. */
- zvni_mac_del(zvni, mac);
+ /* Update all the neigh entries associated with this mac */
+ zvni_process_neigh_on_local_mac_del(zvrf, zvni, mac);
+
+ /*
+ * If there are no neigh associated with the mac delete the mac
+ * else mark it as AUTO for forward reference
+ */
+ if (!listcount(mac->neigh_list)) {
+ zvni_mac_del(zvni, mac);
+ } else {
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ }
return 0;
}
@@ -2584,6 +3592,13 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
? 1
: 0;
+
+ /*
+ * return if nothing has changed.
+ * inform bgp if sticky flag has changed
+ * update locally and do not inform bgp if local
+ * parameters like interface has changed
+ */
if (mac_sticky == sticky
&& mac->fwd_info.local.ifindex == ifp->ifindex
&& mac->fwd_info.local.vid == vid) {
@@ -2598,9 +3613,27 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
ifp->name, ifp->ifindex, vid,
zvni->vni);
return 0;
+ } else if (mac_sticky != sticky) {
+ add = 1;
+ } else {
+ add = 0; /* This is an update of local
+ interface. */
+ }
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ /*
+ * If we have already learned the MAC as a remote sticky
+ * MAC,
+ * this is a operator error and we must log a warning
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
+ zlog_warn(
+ "MAC %s is already learnt as a remote sticky mac behind VTEP %s VNI %d",
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ inet_ntoa(mac->fwd_info.r_vtep_ip),
+ zvni->vni);
+ return 0;
}
-
- add = 0; /* This is an update of local interface. */
}
}
@@ -2621,8 +3654,9 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
/* Set "local" forwarding info. */
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.vid = vid;
@@ -2632,9 +3666,11 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
/* Inform BGP if required. */
- if (add)
+ if (add) {
+ zvni_process_neigh_on_local_mac_add(zvrf, zvni, mac);
return zvni_mac_send_add_to_client(zvrf, zvni->vni, macaddr,
sticky);
+ }
return 0;
}
@@ -2766,6 +3802,104 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length,
}
/*
+ * Add/Del gateway macip to evpn
+ * g/w can be:
+ * 1. SVI interface on a vlan aware bridge
+ * 2. SVI interface on a vlan unaware bridge
+ * 3. vrr interface (MACVLAN) associated to a SVI
+ * We advertise macip routes for an interface if it is associated to VxLan vlan
+ */
+int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
+ int add)
+{
+ struct ipaddr ip;
+ struct ethaddr macaddr;
+ zebra_vni_t *zvni = NULL;
+ struct zebra_vrf *zvrf = NULL;
+
+ memset(&ip, 0, sizeof(struct ipaddr));
+ memset(&macaddr, 0, sizeof(struct ethaddr));
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
+ if (!zvrf)
+ return -1;
+
+ if (!EVPN_ENABLED(zvrf))
+ return 0;
+
+ if (IS_ZEBRA_IF_MACVLAN(ifp)) {
+ struct interface *svi_if =
+ NULL; /* SVI corresponding to the MACVLAN */
+ struct zebra_if *ifp_zif =
+ NULL; /* Zebra daemon specific info for MACVLAN */
+ struct zebra_if *svi_if_zif =
+ NULL; /* Zebra daemon specific info for SVI*/
+
+ ifp_zif = ifp->info;
+ if (!ifp_zif)
+ return -1;
+
+ svi_if = ifp_zif->link;
+ if (!svi_if) {
+ zlog_err("%u:MACVLAN %s(%u) without link information",
+ ifp->vrf_id, ifp->name, ifp->ifindex);
+ return -1;
+ }
+
+ if (IS_ZEBRA_IF_VLAN(svi_if)) {
+ svi_if_zif = svi_if->info;
+ if (svi_if_zif)
+ zvni = zvni_map_svi(svi_if, svi_if_zif->link);
+ } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
+ zvni = zvni_map_svi(svi_if, svi_if);
+ }
+ } else if (IS_ZEBRA_IF_VLAN(ifp)) {
+ struct zebra_if *svi_if_zif =
+ NULL; /* Zebra daemon specific info for SVI*/
+
+ svi_if_zif = ifp->info;
+ if (svi_if_zif)
+ zvni = zvni_map_svi(ifp, svi_if_zif->link);
+ } else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
+ zvni = zvni_map_svi(ifp, ifp);
+ }
+
+ if (!zvni)
+ return 0;
+
+ if (!zvni->vxlan_if) {
+ zlog_err("VNI %u hash %p doesn't have intf upon MACVLAN up",
+ zvni->vni, zvni);
+ return -1;
+ }
+
+
+ /* check if we are advertising gw macip routes */
+ if (!advertise_gw_macip_enabled(zvrf, zvni))
+ return 0;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ if (p->family == AF_INET) {
+ ip.ipa_type = IPADDR_V4;
+ memcpy(&(ip.ipaddr_v4), &(p->u.prefix4),
+ sizeof(struct in_addr));
+ } else if (p->family == AF_INET6) {
+ ip.ipa_type = IPADDR_V6;
+ memcpy(&(ip.ipaddr_v6), &(p->u.prefix6),
+ sizeof(struct in6_addr));
+ }
+
+
+ if (add)
+ zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
+ else
+ zvni_gw_macip_del(ifp, zvni, &ip);
+
+ return 0;
+}
+
+/*
* Handle SVI interface going down. At this point, this is a NOP since
* the kernel deletes the neighbor entries on this SVI (if any).
*/
@@ -3124,6 +4258,98 @@ int zebra_vxlan_if_add(struct interface *ifp)
}
/*
+ * Handle message from client to enable/disable advertisement of g/w macip
+ * routes
+ */
+int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock,
+ u_short length, struct zebra_vrf *zvrf)
+{
+ struct stream *s;
+ int advertise;
+ vni_t vni = 0;
+ zebra_vni_t *zvni = NULL;
+
+ s = client->ibuf;
+ advertise = stream_getc(s);
+ vni = stream_get3(s);
+
+ if (!vni) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%u:EVPN gateway macip Adv %s, currently %s",
+ zvrf_id(zvrf),
+ advertise ? "enabled" : "disabled",
+ advertise_gw_macip_enabled(zvrf, NULL)
+ ? "enabled"
+ : "disabled");
+
+ if (zvrf->advertise_gw_macip == advertise)
+ return 0;
+
+ zvrf->advertise_gw_macip = advertise;
+
+ if (advertise_gw_macip_enabled(zvrf, zvni))
+ hash_iterate(zvrf->vni_table,
+ zvni_gw_macip_add_for_vni_hash, zvrf);
+ else
+ hash_iterate(zvrf->vni_table,
+ zvni_gw_macip_del_for_vni_hash, zvrf);
+
+ } else {
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *vrr_if = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u:EVPN gateway macip Adv %s on VNI %d , currently %s",
+ zvrf_id(zvrf),
+ advertise ? "enabled" : "disabled", vni,
+ advertise_gw_macip_enabled(zvrf, zvni)
+ ? "enabled"
+ : "disabled");
+
+ zvni = zvni_lookup(zvrf, vni);
+ if (!zvni)
+ return 0;
+
+ if (zvni->advertise_gw_macip == advertise)
+ return 0;
+
+ zvni->advertise_gw_macip = advertise;
+
+ zif = zvni->vxlan_if->info;
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
+ zif->brslave_info.br_if);
+ if (!vlan_if)
+ return 0;
+
+ if (advertise_gw_macip_enabled(zvrf, zvni)) {
+ /* Add primary SVI MAC-IP */
+ zvni_add_macip_for_intf(vlan_if, zvni);
+
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_add_macip_for_intf(vrr_if, zvni);
+ } else {
+ /* Del primary MAC-IP */
+ zvni_del_macip_for_intf(vlan_if, zvni);
+
+ /* Del VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_del_macip_for_intf(vrr_if, zvni);
+ }
+ }
+
+ return 0;
+}
+
+
+/*
* Handle message from client to learn (or stop learning) about VNIs and MACs.
* When enabled, the VNI hash table will be built and MAC FDB table read;
* when disabled, the entries should be deleted and remote VTEPs and MACs
@@ -3151,6 +4377,10 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock,
/* Build VNI hash table and inform BGP. */
zvni_build_hash_table(zvrf);
+ /* Add all SVI (L3 GW) MACs to BGP*/
+ hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash,
+ zvrf);
+
/* Read the MAC FDB */
macfdb_read(zvrf->zns);
@@ -3182,4 +4412,5 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
{
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+ hash_free(zvrf->vni_table);
}
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index f9ecd8333d..f7c1afc959 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -41,33 +41,44 @@
#define ZEBRA_VXLIF_MASTER_CHANGE 0x2
#define ZEBRA_VXLIF_VLAN_CHANGE 0x4
+#define VNI_STR_LEN 32
+
extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni);
+ vni_t vni, u_char use_json);
extern void zebra_vxlan_print_macs_all_vni(struct vty *vty,
- struct zebra_vrf *zvrf);
+ struct zebra_vrf *zvrf,
+ u_char use_json);
extern void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf,
- struct in_addr vtep_ip);
+ struct in_addr vtep_ip,
+ u_char use_json);
extern void zebra_vxlan_print_specific_mac_vni(struct vty *vty,
struct zebra_vrf *zvrf,
vni_t vni, struct ethaddr *mac);
extern void zebra_vxlan_print_macs_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni,
- struct in_addr vtep_ip);
+ struct in_addr vtep_ip,
+ u_char use_json);
extern void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni);
+ vni_t vni, u_char use_json);
extern void zebra_vxlan_print_neigh_all_vni(struct vty *vty,
- struct zebra_vrf *zvrf);
+ struct zebra_vrf *zvrf,
+ u_char use_json);
extern void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
struct zebra_vrf *zvrf,
- vni_t vni, struct ipaddr *ip);
+ vni_t vni, struct ipaddr *ip,
+ u_char use_json);
extern void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni,
- struct in_addr vtep_ip);
+ struct in_addr vtep_ip,
+ u_char use_json);
extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni);
-extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf);
+ vni_t vni, u_char use_json);
+extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json);
+extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
+ int add);
extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_svi_down(struct interface *ifp,
struct interface *link_if);
@@ -104,6 +115,9 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock,
+ u_short length,
+ struct zebra_vrf *zvrf);
extern int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock,
u_short length,
struct zebra_vrf *zvrf);
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index fbde722927..8539311eab 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -63,6 +63,9 @@ struct zebra_vni_t_ {
/* VNI - key */
vni_t vni;
+ /* Flag for advertising gw macip */
+ u_int8_t advertise_gw_macip;
+
/* Corresponding VxLAN interface. */
struct interface *vxlan_if;
@@ -112,6 +115,9 @@ struct zebra_mac_t_ {
} fwd_info;
u_int32_t neigh_refcnt;
+
+ /* List of neigh associated with this mac */
+ struct list *neigh_list;
};
/*
@@ -132,10 +138,21 @@ struct mac_walk_ctx {
struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */
- struct vty *vty; /* Used by VTY handlers */
- u_int32_t count; /* Used by VTY handlers */
+ struct vty *vty; /* Used by VTY handlers */
+ u_int32_t count; /* Used by VTY handlers */
+ struct json_object *json; /* Used for JSON Output */
};
+enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
+
+#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE
+
+#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE
+
+#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE
+
+#define ZEBRA_NEIGH_SET_INACTIVE(n) n->state = ZEBRA_NEIGH_INACTIVE
+
/*
* Neighbor hash table.
*
@@ -158,8 +175,10 @@ struct zebra_neigh_t_ {
ifindex_t ifindex;
u_int32_t flags;
-#define ZEBRA_NEIGH_LOCAL 0x01
-#define ZEBRA_NEIGH_REMOTE 0x02
+#define ZEBRA_NEIGH_LOCAL 0x01
+#define ZEBRA_NEIGH_REMOTE 0x02
+
+ enum zebra_neigh_state state;
/* Remote VTEP IP - applicable only for remote neighbors. */
struct in_addr r_vtep_ip;
@@ -183,9 +202,10 @@ struct neigh_walk_ctx {
struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */
- struct vty *vty; /* Used by VTY handlers */
- u_int32_t count; /* Used by VTY handlers */
- u_char addr_width; /* Used by VTY handlers */
+ struct vty *vty; /* Used by VTY handlers */
+ u_int32_t count; /* Used by VTY handlers */
+ u_char addr_width; /* Used by VTY handlers */
+ struct json_object *json; /* Used for JSON Output */
};
#endif /* _ZEBRA_VXLAN_PRIVATE_H */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index bdb7755b63..5ee6c6d1f3 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -19,6 +19,7 @@
*/
#include <zebra.h>
+#include <sys/un.h>
#include "prefix.h"
#include "command.h"
@@ -38,6 +39,7 @@
#include "buffer.h"
#include "nexthop.h"
#include "vrf.h"
+#include "libfrr.h"
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
@@ -2531,6 +2533,9 @@ static int zebra_client_read(struct thread *thread)
case ZEBRA_FEC_UNREGISTER:
zserv_fec_unregister(client, sock, length);
break;
+ case ZEBRA_ADVERTISE_DEFAULT_GW:
+ zebra_vxlan_advertise_gw_macip(client, sock, length, zvrf);
+ break;
case ZEBRA_ADVERTISE_ALL_VNI:
zebra_vxlan_advertise_all_vni(client, sock, length, zvrf);
break;
@@ -2605,116 +2610,59 @@ static int zebra_accept(struct thread *thread)
return 0;
}
-#ifdef HAVE_TCP_ZEBRA
-/* Make zebra's server socket. */
-static void zebra_serv()
-{
- int ret;
- int accept_sock;
- struct sockaddr_in addr;
-
- accept_sock = socket(AF_INET, SOCK_STREAM, 0);
-
- if (accept_sock < 0) {
- zlog_warn("Can't create zserv stream socket: %s",
- safe_strerror(errno));
- zlog_warn(
- "zebra can't provice full functionality due to above error");
- return;
- }
-
- memset(&addr, 0, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(ZEBRA_PORT);
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- addr.sin_len = sizeof(struct sockaddr_in);
-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- sockopt_reuseaddr(accept_sock);
- sockopt_reuseport(accept_sock);
-
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
-
- ret = bind(accept_sock, (struct sockaddr *)&addr,
- sizeof(struct sockaddr_in));
- if (ret < 0) {
- zlog_warn("Can't bind to stream socket: %s",
- safe_strerror(errno));
- zlog_warn(
- "zebra can't provice full functionality due to above error");
- close(accept_sock); /* Avoid sd leak. */
- return;
- }
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
- ret = listen(accept_sock, 1);
- if (ret < 0) {
- zlog_warn("Can't listen to stream socket: %s",
- safe_strerror(errno));
- zlog_warn(
- "zebra can't provice full functionality due to above error");
- close(accept_sock); /* Avoid sd leak. */
- return;
- }
-
- zebra_event(ZEBRA_SERV, accept_sock, NULL);
-}
-#else /* HAVE_TCP_ZEBRA */
-
-/* For sockaddr_un. */
-#include <sys/un.h>
-
-/* zebra server UNIX domain socket. */
-static void zebra_serv_un(const char *path)
+/* Make zebra server socket, wiping any existing one (see bug #403). */
+void zebra_zserv_socket_init(char *path)
{
int ret;
- int sock, len;
- struct sockaddr_un serv;
+ int sock;
mode_t old_mask;
+ struct sockaddr_storage sa;
+ socklen_t sa_len;
- /* First of all, unlink existing socket */
- unlink(path);
+ if (!frr_zclient_addr(&sa, &sa_len, path))
+ /* should be caught in zebra main() */
+ return;
/* Set umask */
old_mask = umask(0077);
/* Make UNIX domain socket. */
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ sock = socket(sa.ss_family, SOCK_STREAM, 0);
if (sock < 0) {
- zlog_warn("Can't create zserv unix socket: %s",
+ zlog_warn("Can't create zserv socket: %s",
safe_strerror(errno));
zlog_warn(
"zebra can't provide full functionality due to above error");
return;
}
- /* Make server socket. */
- memset(&serv, 0, sizeof(struct sockaddr_un));
- serv.sun_family = AF_UNIX;
- strncpy(serv.sun_path, path, strlen(path));
-#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
- len = serv.sun_len = SUN_LEN(&serv);
-#else
- len = sizeof(serv.sun_family) + strlen(serv.sun_path);
-#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
-
- ret = bind(sock, (struct sockaddr *)&serv, len);
+ if (sa.ss_family != AF_UNIX) {
+ sockopt_reuseaddr(sock);
+ sockopt_reuseport(sock);
+ } else {
+ struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
+ if (suna->sun_path[0])
+ unlink(suna->sun_path);
+ }
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog_err("Can't raise privileges");
+
+ ret = bind(sock, (struct sockaddr *)&sa, sa_len);
if (ret < 0) {
- zlog_warn("Can't bind to unix socket %s: %s", path,
+ zlog_warn("Can't bind zserv socket on %s: %s", path,
safe_strerror(errno));
zlog_warn(
"zebra can't provide full functionality due to above error");
close(sock);
return;
}
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog_err("Can't lower privileges");
ret = listen(sock, 5);
if (ret < 0) {
- zlog_warn("Can't listen to unix socket %s: %s", path,
+ zlog_warn("Can't listen to zserv socket %s: %s", path,
safe_strerror(errno));
zlog_warn(
"zebra can't provide full functionality due to above error");
@@ -2726,7 +2674,6 @@ static void zebra_serv_un(const char *path)
zebra_event(ZEBRA_SERV, sock, NULL);
}
-#endif /* HAVE_TCP_ZEBRA */
static void zebra_event(enum event event, int sock, struct zserv *client)
@@ -3165,13 +3112,3 @@ void zebra_init(void)
/* Route-map */
zebra_route_map_init();
}
-
-/* Make zebra server socket, wiping any existing one (see bug #403). */
-void zebra_zserv_socket_init(char *path)
-{
-#ifdef HAVE_TCP_ZEBRA
- zebra_serv();
-#else
- zebra_serv_un(path ? path : ZEBRA_SERV_PATH);
-#endif /* HAVE_TCP_ZEBRA */
-}