Merge branch 'master' into working/master/bgp-vpn-vrf-leaking
3
.gitignore
vendored
@ -82,3 +82,6 @@ GPATH
|
||||
*.lo
|
||||
compile_commands.json
|
||||
.dirstamp
|
||||
|
||||
# clippy generated source
|
||||
*_clippy.c
|
||||
|
36
alpine/APKBUILD.in
Normal file
@ -0,0 +1,36 @@
|
||||
# Maintainer: Arthur Jones <arthur.jones@riverbed.com>
|
||||
pkgname=frr
|
||||
pkgver=@VERSION@
|
||||
pkgrel=0
|
||||
pkgdesc="Free Range Routing is a fork of quagga"
|
||||
url="https://frrouting.org/"
|
||||
arch="all"
|
||||
license="GPL-2.0"
|
||||
depends="iproute2 json-c c-ares ipsec-tools iproute2"
|
||||
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
||||
acct autoconf automake bash
|
||||
binutils binutils-libs bison bsd-compat-headers build-base
|
||||
c-ares c-ares-dev ca-certificates cryptsetup-libs curl
|
||||
device-mapper-libs expat fakeroot flex fortify-headers gdbm
|
||||
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
|
||||
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
|
||||
libgomp libisoburn libisofs libltdl libressl libssh2
|
||||
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1
|
||||
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
|
||||
patch pax-utils pcre perl pkgconf python2 python2-dev readline
|
||||
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs"
|
||||
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
|
||||
source="$pkgname-$pkgver.tar.gz"
|
||||
|
||||
builddir="$srcdir"/$pkgname-$pkgver
|
||||
|
||||
build() {
|
||||
cd "$builddir"
|
||||
./configure --prefix=/usr || return 1
|
||||
make || return 1
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$builddir"
|
||||
make DESTDIR="$pkgdir" install || return 1
|
||||
}
|
1
bgpd/.gitignore
vendored
@ -16,4 +16,3 @@ TAGS
|
||||
.arch-ids
|
||||
*~
|
||||
*.loT
|
||||
*clippy.c
|
||||
|
@ -2107,6 +2107,51 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
|
||||
return BGP_ATTR_PARSE_PROCEED;
|
||||
}
|
||||
|
||||
/* PMSI tunnel attribute (RFC 6514)
|
||||
* Basic validation checks done here.
|
||||
*/
|
||||
static bgp_attr_parse_ret_t
|
||||
bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
|
||||
{
|
||||
struct peer *const peer = args->peer;
|
||||
struct attr *const attr = args->attr;
|
||||
const bgp_size_t length = args->length;
|
||||
u_int8_t tnl_type;
|
||||
|
||||
/* Verify that the receiver is expecting "ingress replication" as we
|
||||
* can only support that.
|
||||
*/
|
||||
if (length < 2) {
|
||||
zlog_err("Bad PMSI tunnel attribute length %d", length);
|
||||
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
|
||||
args->total);
|
||||
}
|
||||
stream_getc(peer->curr); /* Flags */
|
||||
tnl_type = stream_getc(peer->curr);
|
||||
if (tnl_type > PMSI_TNLTYPE_MAX) {
|
||||
zlog_err("Invalid PMSI tunnel attribute type %d", tnl_type);
|
||||
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
|
||||
args->total);
|
||||
}
|
||||
if (tnl_type == PMSI_TNLTYPE_INGR_REPL) {
|
||||
if (length != 9) {
|
||||
zlog_err("Bad PMSI tunnel attribute length %d for IR",
|
||||
length);
|
||||
return bgp_attr_malformed(
|
||||
args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
|
||||
args->total);
|
||||
}
|
||||
}
|
||||
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
||||
attr->pmsi_tnl_type = tnl_type;
|
||||
|
||||
/* Forward read pointer of input stream. */
|
||||
stream_forward_getp(peer->curr, length - 2);
|
||||
|
||||
return BGP_ATTR_PARSE_PROCEED;
|
||||
}
|
||||
|
||||
/* BGP unknown attribute treatment. */
|
||||
static bgp_attr_parse_ret_t bgp_attr_unknown(struct bgp_attr_parser_args *args)
|
||||
{
|
||||
@ -2440,6 +2485,9 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
|
||||
case BGP_ATTR_PREFIX_SID:
|
||||
ret = bgp_attr_prefix_sid(&attr_args, mp_update);
|
||||
break;
|
||||
case BGP_ATTR_PMSI_TUNNEL:
|
||||
ret = bgp_attr_pmsi_tunnel(&attr_args);
|
||||
break;
|
||||
default:
|
||||
ret = bgp_attr_unknown(&attr_args);
|
||||
break;
|
||||
@ -3263,7 +3311,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
|
||||
stream_putc(s, 9); // Length
|
||||
stream_putc(s, 0); // Flags
|
||||
stream_putc(s, 6); // Tunnel type: Ingress Replication (6)
|
||||
stream_putc(s, PMSI_TNLTYPE_INGR_REPL); // IR (6)
|
||||
stream_put(s, &(attr->label),
|
||||
BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
|
||||
stream_put_ipv4(s, attr->nexthop.s_addr);
|
||||
|
@ -66,6 +66,8 @@
|
||||
#define BGP_PREFIX_SID_IPV6_LENGTH 19
|
||||
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
|
||||
|
||||
/* PMSI tunnel types (RFC 6514) */
|
||||
|
||||
struct bgp_attr_encap_subtlv {
|
||||
struct bgp_attr_encap_subtlv *next; /* for chaining */
|
||||
/* Reference count of this attribute. */
|
||||
@ -96,6 +98,18 @@ struct overlay_index {
|
||||
union gw_addr gw_ip;
|
||||
};
|
||||
|
||||
enum pta_type {
|
||||
PMSI_TNLTYPE_NO_INFO = 0,
|
||||
PMSI_TNLTYPE_RSVP_TE_P2MP,
|
||||
PMSI_TNLTYPE_MLDP_P2MP,
|
||||
PMSI_TNLTYPE_PIM_SSM,
|
||||
PMSI_TNLTYPE_PIM_SM,
|
||||
PMSI_TNLTYPE_PIM_BIDIR,
|
||||
PMSI_TNLTYPE_INGR_REPL,
|
||||
PMSI_TNLTYPE_MLDP_MP2MP,
|
||||
PMSI_TNLTYPE_MAX = PMSI_TNLTYPE_MLDP_MP2MP
|
||||
};
|
||||
|
||||
/* BGP core attribute structure. */
|
||||
struct attr {
|
||||
/* AS Path structure */
|
||||
@ -119,6 +133,9 @@ struct attr {
|
||||
/* Path origin attribute */
|
||||
u_char origin;
|
||||
|
||||
/* PMSI tunnel type (RFC 6514). */
|
||||
enum pta_type pmsi_tnl_type;
|
||||
|
||||
/* has the route-map changed any attribute?
|
||||
Used on the peer outbound side. */
|
||||
u_int32_t rmap_change_flags;
|
||||
|
@ -162,7 +162,6 @@ static const struct message bgp_notify_capability_msg[] = {
|
||||
const char *bgp_origin_str[] = {"i", "e", "?"};
|
||||
const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"};
|
||||
|
||||
|
||||
/* Given a string return a pointer the corresponding peer structure */
|
||||
static struct peer *bgp_find_peer(struct vty *vty, const char *peer_str)
|
||||
{
|
||||
@ -417,6 +416,10 @@ int bgp_dump_attr(struct attr *attr, char *buf, size_t size)
|
||||
inet_ntoa(attr->cluster->list[i]));
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)))
|
||||
snprintf(buf + strlen(buf), size - strlen(buf),
|
||||
", pmsi tnltype %u", attr->pmsi_tnl_type);
|
||||
|
||||
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
|
||||
snprintf(buf + strlen(buf), size - strlen(buf), ", path %s",
|
||||
aspath_print(attr->aspath));
|
||||
|
@ -142,6 +142,7 @@ struct bgp_debug_filter {
|
||||
#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
|
||||
|
||||
extern const char *bgp_type_str[];
|
||||
extern const char *pmsi_tnltype_str[];
|
||||
|
||||
extern int bgp_dump_attr(struct attr *, char *, size_t);
|
||||
extern int bgp_debug_peer_updout_enabled(char *host);
|
||||
|
202
bgpd/bgp_evpn.c
@ -474,6 +474,17 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
bgp_evpn_derive_auto_rt_export(bgp, vpn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert nexthop (remote VTEP IP) into an IPv6 address.
|
||||
*/
|
||||
static void evpn_convert_nexthop_to_ipv6(struct attr *attr)
|
||||
{
|
||||
if (BGP_ATTR_NEXTHOP_AFI_IP6(attr))
|
||||
return;
|
||||
ipv4_to_ipv4_mapped_ipv6(&attr->mp_nexthop_global, attr->nexthop);
|
||||
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add (update) or delete MACIP from zebra.
|
||||
*/
|
||||
@ -622,17 +633,17 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
|
||||
}
|
||||
|
||||
/*
|
||||
* Build extended communities for EVPN route. RT and ENCAP are
|
||||
* applicable to all routes.
|
||||
* TODO: currently kernel doesnt support ipv6 routes with ipv4 nexthops.
|
||||
* This means that we can't do symmetric routing for ipv6 hosts routes
|
||||
* in the same way as ipv4 host routes.
|
||||
* We wont attach l3-vni related RTs for ipv6 routes.
|
||||
* For now, We will only adevrtise ipv4 host routes
|
||||
* with L3-VNI related ext-comm.
|
||||
* Build extended communities for EVPN route.
|
||||
* This function is applicable for type-2 and type-3 routes. The layer-2 RT
|
||||
* and ENCAP extended communities are applicable for all routes.
|
||||
* The default gateway extended community and MAC mobility (sticky) extended
|
||||
* community are added as needed based on passed settings - only for type-2
|
||||
* routes. Likewise, the layer-3 RT and Router MAC extended communities are
|
||||
* added, if present, based on passed settings - only for non-link-local
|
||||
* type-2 routes.
|
||||
*/
|
||||
static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
afi_t afi)
|
||||
int add_l3_ecomm)
|
||||
{
|
||||
struct ecommunity ecom_encap;
|
||||
struct ecommunity ecom_sticky;
|
||||
@ -662,11 +673,10 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
|
||||
attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
|
||||
|
||||
/*
|
||||
* only attach l3-vni export rts for ipv4 address family and if we are
|
||||
* advertising both the labels in type-2 routes
|
||||
/* Add the export RTs for L3VNI if told to - caller determines
|
||||
* when this should be done.
|
||||
*/
|
||||
if (afi == AFI_IP && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
|
||||
if (add_l3_ecomm) {
|
||||
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
|
||||
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
|
||||
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
|
||||
@ -676,6 +686,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
}
|
||||
}
|
||||
|
||||
/* Add MAC mobility (sticky) if needed. */
|
||||
if (attr->sticky) {
|
||||
seqnum = 0;
|
||||
memset(&ecom_sticky, 0, sizeof(ecom_sticky));
|
||||
@ -686,12 +697,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
ecommunity_merge(attr->ecommunity, &ecom_sticky);
|
||||
}
|
||||
|
||||
/*
|
||||
* only attach l3-vni rmac for ipv4 address family and if we are
|
||||
* advertising both the labels in type-2 routes
|
||||
*/
|
||||
if (afi == AFI_IP && !is_zero_mac(&attr->rmac)
|
||||
&& CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
|
||||
/* Add RMAC, if told to. */
|
||||
if (add_l3_ecomm) {
|
||||
memset(&ecom_rmac, 0, sizeof(ecom_rmac));
|
||||
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
|
||||
ecom_rmac.size = 1;
|
||||
@ -700,6 +707,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
ecommunity_merge(attr->ecommunity, &ecom_rmac);
|
||||
}
|
||||
|
||||
/* Add default gateway, if needed. */
|
||||
if (attr->default_gw) {
|
||||
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
|
||||
encode_default_gw_extcomm(&eval_default_gw);
|
||||
@ -1260,6 +1268,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
struct bgp_node *rn;
|
||||
struct attr attr;
|
||||
struct attr *attr_new;
|
||||
int add_l3_ecomm = 0;
|
||||
struct bgp_info *ri;
|
||||
afi_t afi = AFI_L2VPN;
|
||||
safi_t safi = SAFI_EVPN;
|
||||
@ -1279,14 +1288,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE)
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
||||
|
||||
/* router mac is only needed for type-2 and type-5 routes */
|
||||
/* router mac is only needed for type-2 routes here. */
|
||||
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
|
||||
bgpevpn_get_rmac(vpn, &attr.rmac);
|
||||
vni2label(vpn->vni, &(attr.label));
|
||||
|
||||
/* Set up RT and ENCAP extended community. */
|
||||
build_evpn_route_extcomm(
|
||||
vpn, &attr, IS_EVPN_PREFIX_IPADDR_V4(p) ? AFI_IP : AFI_IP6);
|
||||
/* Include L3 VNI related RTs and RMAC for type-2 routes, if they're
|
||||
* IPv4 or IPv6 global addresses and we're advertising L3VNI with
|
||||
* these routes.
|
||||
*/
|
||||
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
|
||||
(IS_EVPN_PREFIX_IPADDR_V4(p) ||
|
||||
!IN6_IS_ADDR_LINKLOCAL(&p->prefix.ip.ipaddr_v6)) &&
|
||||
CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS))
|
||||
add_l3_ecomm = 1;
|
||||
|
||||
/* Set up extended community. */
|
||||
build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
|
||||
|
||||
/* First, create (or fetch) route node within the VNI. */
|
||||
/* NOTE: There is no RD here. */
|
||||
@ -1466,22 +1484,20 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
struct attr attr;
|
||||
struct attr attr_sticky;
|
||||
struct attr attr_def_gw;
|
||||
struct attr attr_ip6;
|
||||
struct attr attr_sticky_ip6;
|
||||
struct attr attr_def_gw_ip6;
|
||||
struct attr attr_ip6_ll;
|
||||
struct attr *attr_new;
|
||||
int add_l3_ecomm = 0;
|
||||
|
||||
afi = AFI_L2VPN;
|
||||
safi = SAFI_EVPN;
|
||||
memset(&attr, 0, sizeof(struct attr));
|
||||
memset(&attr_sticky, 0, sizeof(struct attr));
|
||||
memset(&attr_def_gw, 0, sizeof(struct attr));
|
||||
memset(&attr_ip6, 0, sizeof(struct attr));
|
||||
memset(&attr_sticky_ip6, 0, sizeof(struct attr));
|
||||
memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
|
||||
memset(&attr_ip6_ll, 0, sizeof(struct attr));
|
||||
|
||||
/* Build path-attribute - all type-2 routes for this VNI will share the
|
||||
* same path attribute.
|
||||
/* Build path-attribute - multiple type-2 routes for this VNI will share
|
||||
* the same path attribute, but we need separate structures for sticky
|
||||
* MACs, default gateway and IPv6 link-local addresses (no L3 RT/RMAC).
|
||||
*/
|
||||
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP);
|
||||
@ -1500,31 +1516,21 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_def_gw.default_gw = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
|
||||
bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP);
|
||||
attr_ip6.nexthop = vpn->originator_ip;
|
||||
attr_ip6.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
bgpevpn_get_rmac(vpn, &attr_ip6.rmac);
|
||||
attr_sticky_ip6.nexthop = vpn->originator_ip;
|
||||
attr_sticky_ip6.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_sticky_ip6.sticky = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac);
|
||||
attr_def_gw_ip6.nexthop = vpn->originator_ip;
|
||||
attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_def_gw_ip6.default_gw = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac);
|
||||
bgp_attr_default_set(&attr_ip6_ll, BGP_ORIGIN_IGP);
|
||||
attr_ip6_ll.nexthop = vpn->originator_ip;
|
||||
attr_ip6_ll.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_ip6_ll.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
|
||||
/* Set up RT, ENCAP and sticky MAC extended community. */
|
||||
build_evpn_route_extcomm(vpn, &attr, AFI_IP);
|
||||
build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
|
||||
build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
|
||||
build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
|
||||
build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
|
||||
build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
|
||||
/* Add L3 VNI RTs and RMAC for non IPv6 link-local attributes if
|
||||
* using L3 VNI for type-2 routes also.
|
||||
*/
|
||||
if (CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS))
|
||||
add_l3_ecomm = 1;
|
||||
|
||||
build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
|
||||
build_evpn_route_extcomm(vpn, &attr_sticky, add_l3_ecomm);
|
||||
build_evpn_route_extcomm(vpn, &attr_def_gw, add_l3_ecomm);
|
||||
build_evpn_route_extcomm(vpn, &attr_ip6_ll, 0);
|
||||
|
||||
/* Walk this VNI's route table and update local type-2 routes. For any
|
||||
* routes updated, update corresponding entry in the global table too.
|
||||
@ -1538,7 +1544,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
||||
continue;
|
||||
|
||||
if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
|
||||
if (IS_EVPN_PREFIX_IPADDR_V6(evp) &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&evp->prefix.ip.ipaddr_v6))
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_ip6_ll, 0, 1, &ri, 0);
|
||||
else {
|
||||
if (evpn_route_is_sticky(bgp, rn))
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_sticky, 0, 1, &ri,
|
||||
@ -1550,19 +1560,6 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
else
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr, 0, 1, &ri, 0);
|
||||
} else {
|
||||
if (evpn_route_is_sticky(bgp, rn))
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_sticky_ip6, 0, 1,
|
||||
&ri, 0);
|
||||
else if (evpn_route_is_def_gw(bgp, rn))
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_def_gw_ip6, 0, 1,
|
||||
&ri, 0);
|
||||
else
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_ip6, 0, 1, &ri,
|
||||
0);
|
||||
}
|
||||
|
||||
/* If a local route exists for this prefix, we need to update
|
||||
@ -1593,11 +1590,9 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
|
||||
/* Unintern temporary. */
|
||||
aspath_unintern(&attr.aspath);
|
||||
aspath_unintern(&attr_ip6.aspath);
|
||||
aspath_unintern(&attr_sticky.aspath);
|
||||
aspath_unintern(&attr_sticky_ip6.aspath);
|
||||
aspath_unintern(&attr_def_gw.aspath);
|
||||
aspath_unintern(&attr_def_gw_ip6.aspath);
|
||||
aspath_unintern(&attr_ip6_ll.aspath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1791,6 +1786,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
{
|
||||
struct bgp_node *rn;
|
||||
struct bgp_info *ri;
|
||||
struct attr attr;
|
||||
struct attr *attr_new;
|
||||
int ret = 0;
|
||||
struct prefix p;
|
||||
@ -1827,6 +1823,15 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
} else
|
||||
return 0;
|
||||
|
||||
/* EVPN routes currently only support a IPv4 next hop which corresponds
|
||||
* to the remote VTEP. When importing into a VRF, if it is IPv6 host
|
||||
* route, we have to convert the next hop to an IPv4-mapped address
|
||||
* for the rest of the code to flow through.
|
||||
*/
|
||||
bgp_attr_dup(&attr, parent_ri->attr);
|
||||
if (afi == AFI_IP6)
|
||||
evpn_convert_nexthop_to_ipv6(&attr);
|
||||
|
||||
/* Check if route entry is already present. */
|
||||
for (ri = rn->info; ri; ri = ri->next)
|
||||
if (ri->extra
|
||||
@ -1835,7 +1840,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
|
||||
if (!ri) {
|
||||
/* Add (or update) attribute to hash. */
|
||||
attr_new = bgp_attr_intern(parent_ri->attr);
|
||||
attr_new = bgp_attr_intern(&attr);
|
||||
|
||||
/* Create new route with its attribute. */
|
||||
ri = info_make(parent_ri->type, parent_ri->sub_type, 0,
|
||||
@ -1850,21 +1855,25 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
}
|
||||
bgp_info_add(rn, ri);
|
||||
} else {
|
||||
if (attrhash_cmp(ri->attr, parent_ri->attr)
|
||||
if (attrhash_cmp(ri->attr, &attr)
|
||||
&& !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
|
||||
bgp_unlock_node(rn);
|
||||
return 0;
|
||||
}
|
||||
/* The attribute has changed. */
|
||||
/* Add (or update) attribute to hash. */
|
||||
attr_new = bgp_attr_intern(parent_ri->attr);
|
||||
attr_new = bgp_attr_intern(&attr);
|
||||
|
||||
/* Restore route, if needed. */
|
||||
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
|
||||
bgp_info_restore(rn, ri);
|
||||
|
||||
/* Mark if nexthop has changed. */
|
||||
if (!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop))
|
||||
if ((afi == AFI_IP &&
|
||||
!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop)) ||
|
||||
(afi == AFI_IP6 &&
|
||||
!IPV6_ADDR_SAME(&ri->attr->mp_nexthop_global,
|
||||
&attr_new->mp_nexthop_global)))
|
||||
SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED);
|
||||
|
||||
/* Unintern existing, set to new. */
|
||||
@ -2577,10 +2586,12 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
|
||||
{
|
||||
/* delete all ipv4 routes and withdraw from peers */
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
|
||||
if (advertise_type5_routes(bgp_vrf, AFI_IP))
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
|
||||
|
||||
/* delete all ipv6 routes and withdraw from peers */
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
|
||||
if (advertise_type5_routes(bgp_vrf, AFI_IP6))
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
|
||||
}
|
||||
|
||||
/* update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5
|
||||
@ -2588,10 +2599,12 @@ static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
|
||||
static void update_advertise_vrf_routes(struct bgp *bgp_vrf)
|
||||
{
|
||||
/* update all ipv4 routes */
|
||||
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
|
||||
if (advertise_type5_routes(bgp_vrf, AFI_IP))
|
||||
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
|
||||
|
||||
/* update all ipv6 routes */
|
||||
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
|
||||
if (advertise_type5_routes(bgp_vrf, AFI_IP6))
|
||||
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2922,6 +2935,19 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If PMSI is present, log if it is anything other than IR.
|
||||
* Note: We just simply ignore the values as it is not clear if
|
||||
* doing anything else is better.
|
||||
*/
|
||||
if (attr &&
|
||||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) {
|
||||
if (attr->pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL) {
|
||||
zlog_warn("%u:%s - Rx EVPN Type-3 NLRI with unsupported PTA %d",
|
||||
peer->bgp->vrf_id, peer->host,
|
||||
attr->pmsi_tnl_type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make prefix_rd */
|
||||
prd.family = AF_UNSPEC;
|
||||
prd.prefixlen = 64;
|
||||
@ -3214,10 +3240,6 @@ void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
||||
struct prefix_evpn evp;
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
/* NOTE: Check needed as this is called per-route also. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
build_type5_prefix_from_ip_prefix(&evp, p);
|
||||
ret = delete_evpn_type5_route(bgp_vrf, &evp);
|
||||
if (ret) {
|
||||
@ -3235,10 +3257,6 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
|
||||
struct bgp_node *rn = NULL;
|
||||
struct bgp_info *ri;
|
||||
|
||||
/* Bail out early if we don't have to advertise type-5 routes. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Only care about "selected" routes - non-imported. */
|
||||
@ -3268,10 +3286,6 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
||||
struct prefix_evpn evp;
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
/* NOTE: Check needed as this is called per-route also. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
build_type5_prefix_from_ip_prefix(&evp, p);
|
||||
ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
|
||||
if (ret)
|
||||
@ -3290,10 +3304,6 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
||||
struct bgp_node *rn = NULL;
|
||||
struct bgp_info *ri;
|
||||
|
||||
/* Bail out early if we don't have to advertise type-5 routes. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Need to identify the "selected" route entry to use its
|
||||
|
@ -55,6 +55,25 @@ static inline vni_t label2vni(mpls_label_t *label)
|
||||
return vni;
|
||||
}
|
||||
|
||||
static inline int advertise_type5_routes(struct bgp *bgp_vrf,
|
||||
afi_t afi)
|
||||
{
|
||||
if (!bgp_vrf->l3vni)
|
||||
return 0;
|
||||
|
||||
if (afi == AFI_IP &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||
return 1;
|
||||
|
||||
if (afi == AFI_IP6 &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||
struct prefix *p,
|
||||
struct attr *src_attr, afi_t afi,
|
||||
|
@ -285,6 +285,14 @@ static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp,
|
||||
}
|
||||
}
|
||||
|
||||
static inline int is_evpn_prefix_default(struct prefix *evp)
|
||||
{
|
||||
if (evp->family != AF_EVPN)
|
||||
return 0;
|
||||
|
||||
return ((evp->u.prefix_evpn.ip_prefix_length == 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
|
||||
struct prefix *ip)
|
||||
{
|
||||
@ -352,19 +360,17 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
|
||||
p->prefix.ip.ipaddr_v4 = originator_ip;
|
||||
}
|
||||
|
||||
static inline int advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi)
|
||||
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
|
||||
safi_t safi)
|
||||
{
|
||||
if (!bgp_vrf->l3vni)
|
||||
return 0;
|
||||
|
||||
if (afi == AFI_IP
|
||||
&& CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
||||
if (afi == AFI_IP &&
|
||||
CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
|
||||
return 1;
|
||||
|
||||
if (afi == AFI_IP6
|
||||
&& CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
||||
else if (afi == AFI_IP6 &&
|
||||
CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2419,7 +2419,50 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
|
||||
/*
|
||||
* evpn - enable advertisement of default g/w
|
||||
*/
|
||||
static void evpn_set_advertise_subnet(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf,
|
||||
afi_t afi, int add)
|
||||
{
|
||||
struct prefix ip_prefix;
|
||||
safi_t safi = SAFI_UNICAST; /* ipv4/ipv6 unicast */
|
||||
|
||||
/* form the default prefix 0.0.0.0/0 */
|
||||
memset(&ip_prefix, 0, sizeof(struct prefix));
|
||||
ip_prefix.family = afi2family(afi);
|
||||
ip_prefix.prefixlen = 0;
|
||||
|
||||
if (add) {
|
||||
/* bail if we are already advertising default route */
|
||||
if (evpn_default_originate_set(bgp_vrf, afi, safi))
|
||||
return;
|
||||
|
||||
if (afi == AFI_IP)
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
|
||||
else if (afi == AFI_IP6)
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
|
||||
bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
|
||||
NULL, afi, safi);
|
||||
} else {
|
||||
/* bail out if we havent advertised the default route */
|
||||
if (!evpn_default_originate_set(bgp_vrf, afi, safi))
|
||||
return;
|
||||
if (afi == AFI_IP)
|
||||
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4);
|
||||
else if (afi == AFI_IP6)
|
||||
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6);
|
||||
bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
|
||||
afi, safi);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* evpn - enable advertisement of default g/w
|
||||
*/
|
||||
static void evpn_set_advertise_subnet(struct bgp *bgp,
|
||||
struct bgpevpn *vpn)
|
||||
{
|
||||
if (vpn->advertise_subnet)
|
||||
return;
|
||||
@ -2612,6 +2655,43 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (bgp_evpn_default_originate,
|
||||
bgp_evpn_default_originate_cmd,
|
||||
"default-originate <ipv4 | ipv6>",
|
||||
"originate a default route\n"
|
||||
"ipv4 address family\n"
|
||||
"ipv6 address family\n")
|
||||
{
|
||||
afi_t afi = 0;
|
||||
int idx_afi = 0;
|
||||
struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
|
||||
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
|
||||
evpn_process_default_originate_cmd(bgp_vrf, afi, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_bgp_evpn_default_originate,
|
||||
no_bgp_evpn_default_originate_cmd,
|
||||
"no default-originate <ipv4 | ipv6>",
|
||||
NO_STR
|
||||
"withdraw a default route\n"
|
||||
"ipv4 address family\n"
|
||||
"ipv6 address family\n")
|
||||
{
|
||||
afi_t afi = 0;
|
||||
int idx_afi = 0;
|
||||
struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
|
||||
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
|
||||
evpn_process_default_originate_cmd(bgp_vrf, afi, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (bgp_evpn_advertise_vni_subnet,
|
||||
bgp_evpn_advertise_vni_subnet_cmd,
|
||||
"advertise-subnet",
|
||||
@ -2631,14 +2711,6 @@ DEFUN (bgp_evpn_advertise_vni_subnet,
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!(advertise_type5_routes(bgp_vrf, AFI_IP)
|
||||
|| advertise_type5_routes(bgp_vrf, AFI_IP6))) {
|
||||
vty_out(vty,
|
||||
"%%Please enable ip prefix advertisement under l2vpn evpn in %s",
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
evpn_set_advertise_subnet(bgp, vpn);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -2711,19 +2783,23 @@ DEFUN (bgp_evpn_advertise_type5,
|
||||
/* if we are already advertising ipv4 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
||||
if (!rmap_changed &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||
return CMD_WARNING;
|
||||
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
|
||||
} else {
|
||||
|
||||
/* if we are already advertising ipv6 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
||||
if (!rmap_changed &&
|
||||
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||
return CMD_WARNING;
|
||||
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
|
||||
SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
|
||||
}
|
||||
|
||||
if (rmap_changed) {
|
||||
@ -2766,7 +2842,7 @@ DEFUN (no_bgp_evpn_advertise_type5,
|
||||
argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
|
||||
argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
|
||||
|
||||
if (!(afi == AFI_IP) || (afi == AFI_IP6)) {
|
||||
if (!(afi == AFI_IP || afi == AFI_IP6)) {
|
||||
vty_out(vty,
|
||||
"%%only ipv4 or ipv6 address families are supported");
|
||||
return CMD_WARNING;
|
||||
@ -2780,25 +2856,25 @@ DEFUN (no_bgp_evpn_advertise_type5,
|
||||
|
||||
if (afi == AFI_IP) {
|
||||
|
||||
/* if we are already advertising ipv4 prefix as type-5
|
||||
/* if we are not advertising ipv4 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) {
|
||||
if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
||||
UNSET_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
|
||||
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* if we are already advertising ipv6 prefix as type-5
|
||||
/* if we are not advertising ipv6 prefix as type-5
|
||||
* nothing to do
|
||||
*/
|
||||
if (CHECK_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) {
|
||||
if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
|
||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
||||
UNSET_FLAG(bgp_vrf->vrf_flags,
|
||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4305,12 +4381,22 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
if (bgp->advertise_gw_macip)
|
||||
vty_out(vty, " advertise-default-gw\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||
vty_out(vty, " advertise ipv4 unicast\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||
vty_out(vty, " advertise ipv6 unicast\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
|
||||
vty_out(vty, " default-originate ipv4\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
|
||||
vty_out(vty, " default-originate ipv6\n");
|
||||
|
||||
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
|
||||
vty_out(vty, " rd %s\n",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
|
||||
@ -4373,6 +4459,8 @@ void bgp_ethernetvpn_init(void)
|
||||
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
|
||||
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
|
||||
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
|
||||
install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
|
||||
install_element(BGP_EVPN_NODE, &no_bgp_evpn_default_originate_cmd);
|
||||
|
||||
/* "show bgp l2vpn evpn" commands. */
|
||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
|
||||
|
@ -82,6 +82,21 @@
|
||||
extern const char *bgp_origin_str[];
|
||||
extern const char *bgp_origin_long_str[];
|
||||
|
||||
/* PMSI strings. */
|
||||
#define PMSI_TNLTYPE_STR_NO_INFO "No info"
|
||||
#define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
|
||||
static const struct message bgp_pmsi_tnltype_str[] = {
|
||||
{PMSI_TNLTYPE_NO_INFO, PMSI_TNLTYPE_STR_NO_INFO},
|
||||
{PMSI_TNLTYPE_RSVP_TE_P2MP, "RSVP-TE P2MP"},
|
||||
{PMSI_TNLTYPE_MLDP_P2MP, "mLDP P2MP"},
|
||||
{PMSI_TNLTYPE_PIM_SSM, "PIM-SSM"},
|
||||
{PMSI_TNLTYPE_PIM_SM, "PIM-SM"},
|
||||
{PMSI_TNLTYPE_PIM_BIDIR, "PIM-BIDIR"},
|
||||
{PMSI_TNLTYPE_INGR_REPL, "Ingress Replication"},
|
||||
{PMSI_TNLTYPE_MLDP_MP2MP, "mLDP MP2MP"},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
|
||||
safi_t safi, struct prefix *p,
|
||||
struct prefix_rd *prd)
|
||||
@ -2285,12 +2300,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
|
||||
/* advertise/withdraw type-5 routes */
|
||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||
if (new_select
|
||||
&& (!new_select->extra || !new_select->extra->parent))
|
||||
bgp_evpn_advertise_type5_route(
|
||||
bgp, &rn->p, new_select->attr, afi, safi);
|
||||
else if (old_select
|
||||
&& (!old_select->extra || !old_select->extra->parent))
|
||||
if (advertise_type5_routes(bgp, afi) && new_select &&
|
||||
(!new_select->extra || !new_select->extra->parent))
|
||||
bgp_evpn_advertise_type5_route(bgp, &rn->p,
|
||||
new_select->attr,
|
||||
afi, safi);
|
||||
else if (advertise_type5_routes(bgp, afi) && old_select &&
|
||||
(!old_select->extra || !old_select->extra->parent))
|
||||
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
||||
}
|
||||
|
||||
@ -7197,6 +7213,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||
json_object *json_ext_community = NULL;
|
||||
json_object *json_lcommunity = NULL;
|
||||
json_object *json_last_update = NULL;
|
||||
json_object *json_pmsi = NULL;
|
||||
json_object *json_nexthop_global = NULL;
|
||||
json_object *json_nexthop_ll = NULL;
|
||||
json_object *json_nexthops = NULL;
|
||||
@ -7949,6 +7966,24 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||
json_last_update);
|
||||
} else
|
||||
vty_out(vty, " Last update: %s", ctime(&tbuf));
|
||||
|
||||
/* Line 10 display PMSI tunnel attribute, if present */
|
||||
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
|
||||
const char *str = lookup_msg(bgp_pmsi_tnltype_str,
|
||||
attr->pmsi_tnl_type,
|
||||
PMSI_TNLTYPE_STR_DEFAULT);
|
||||
|
||||
if (json_paths) {
|
||||
json_pmsi = json_object_new_object();
|
||||
json_object_string_add(json_pmsi,
|
||||
"tunnelType", str);
|
||||
json_object_object_add(json_path, "pmsi",
|
||||
json_pmsi);
|
||||
} else
|
||||
vty_out(vty, " PMSI Tunnel Type: %s\n",
|
||||
str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We've constructed the json object for this path, add it to the json
|
||||
|
@ -595,6 +595,24 @@ 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 evpn default-route' */
|
||||
|
||||
/* Match function should return 1 if match is success else 0 */
|
||||
static route_map_result_t route_match_evpn_default_route(void *rule,
|
||||
struct prefix *p,
|
||||
route_map_object_t
|
||||
type, void *object)
|
||||
{
|
||||
if (type == RMAP_BGP && is_evpn_prefix_default(p))
|
||||
return RMAP_MATCH;
|
||||
|
||||
return RMAP_NOMATCH;
|
||||
}
|
||||
|
||||
/* Route map commands for default-route matching. */
|
||||
struct route_map_rule_cmd route_match_evpn_default_route_cmd = {
|
||||
"evpn default-route", route_match_evpn_default_route, NULL, NULL};
|
||||
|
||||
/* `match mac address MAC_ACCESS_LIST' */
|
||||
|
||||
/* Match function should return 1 if match is success else return
|
||||
@ -3254,6 +3272,29 @@ DEFUN (no_match_evpn_vni,
|
||||
RMAP_EVENT_MATCH_DELETED);
|
||||
}
|
||||
|
||||
DEFUN (match_evpn_default_route,
|
||||
match_evpn_default_route_cmd,
|
||||
"match evpn default-route",
|
||||
MATCH_STR
|
||||
EVPN_HELP_STR
|
||||
"default EVPN type-5 route\n")
|
||||
{
|
||||
return bgp_route_match_add(vty, "evpn default-route", NULL,
|
||||
RMAP_EVENT_MATCH_ADDED);
|
||||
}
|
||||
|
||||
DEFUN (no_match_evpn_default_route,
|
||||
no_match_evpn_default_route_cmd,
|
||||
"no match evpn default-route",
|
||||
NO_STR
|
||||
MATCH_STR
|
||||
EVPN_HELP_STR
|
||||
"default EVPN type-5 route\n")
|
||||
{
|
||||
return bgp_route_match_delete(vty, "evpn default-route", NULL,
|
||||
RMAP_EVENT_MATCH_DELETED);
|
||||
}
|
||||
|
||||
DEFUN (match_peer,
|
||||
match_peer_cmd,
|
||||
"match peer <A.B.C.D|X:X::X:X|WORD>",
|
||||
@ -4633,6 +4674,7 @@ void bgp_route_map_init(void)
|
||||
route_map_install_match(&route_match_mac_address_cmd);
|
||||
route_map_install_match(&route_match_evpn_vni_cmd);
|
||||
route_map_install_match(&route_match_evpn_route_type_cmd);
|
||||
route_map_install_match(&route_match_evpn_default_route_cmd);
|
||||
|
||||
route_map_install_set(&route_set_ip_nexthop_cmd);
|
||||
route_map_install_set(&route_set_local_pref_cmd);
|
||||
@ -4669,6 +4711,8 @@ void bgp_route_map_init(void)
|
||||
install_element(RMAP_NODE, &no_match_evpn_vni_cmd);
|
||||
install_element(RMAP_NODE, &match_evpn_route_type_cmd);
|
||||
install_element(RMAP_NODE, &no_match_evpn_route_type_cmd);
|
||||
install_element(RMAP_NODE, &match_evpn_default_route_cmd);
|
||||
install_element(RMAP_NODE, &no_match_evpn_default_route_cmd);
|
||||
|
||||
install_element(RMAP_NODE, &match_aspath_cmd);
|
||||
install_element(RMAP_NODE, &no_match_aspath_cmd);
|
||||
|
@ -7534,16 +7534,14 @@ static void bgp_pthreads_init()
|
||||
.id = PTHREAD_IO,
|
||||
.start = frr_pthread_attr_default.start,
|
||||
.stop = frr_pthread_attr_default.stop,
|
||||
.name = "BGP I/O thread",
|
||||
};
|
||||
struct frr_pthread_attr ka = {
|
||||
.id = PTHREAD_KEEPALIVES,
|
||||
.start = bgp_keepalives_start,
|
||||
.stop = bgp_keepalives_stop,
|
||||
.name = "BGP Keepalives thread",
|
||||
};
|
||||
frr_pthread_new(&io);
|
||||
frr_pthread_new(&ka);
|
||||
frr_pthread_new(&io, "BGP I/O thread");
|
||||
frr_pthread_new(&ka, "BGP Keepalives thread");
|
||||
}
|
||||
|
||||
void bgp_pthreads_run()
|
||||
|
18
bgpd/bgpd.h
@ -319,6 +319,13 @@ struct bgp {
|
||||
#define BGP_CONFIG_DAMPENING (1 << 0)
|
||||
#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 1)
|
||||
|
||||
/* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
|
||||
#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST (1 << 1)
|
||||
#define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST (1 << 2)
|
||||
#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 3)
|
||||
#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 4)
|
||||
|
||||
|
||||
/* Route table for next-hop lookup cache. */
|
||||
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
||||
|
||||
@ -430,12 +437,11 @@ struct bgp {
|
||||
/* vrf flags */
|
||||
uint32_t vrf_flags;
|
||||
#define BGP_VRF_AUTO (1 << 0)
|
||||
#define BGP_VRF_ADVERTISE_IPV4_IN_EVPN (1 << 1)
|
||||
#define BGP_VRF_ADVERTISE_IPV6_IN_EVPN (1 << 2)
|
||||
#define BGP_VRF_IMPORT_RT_CFGD (1 << 3)
|
||||
#define BGP_VRF_EXPORT_RT_CFGD (1 << 4)
|
||||
#define BGP_VRF_RD_CFGD (1 << 5)
|
||||
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 6)
|
||||
#define BGP_VRF_IMPORT_RT_CFGD (1 << 1)
|
||||
#define BGP_VRF_EXPORT_RT_CFGD (1 << 2)
|
||||
#define BGP_VRF_RD_CFGD (1 << 3)
|
||||
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4)
|
||||
|
||||
|
||||
/* unique ID for auto derivation of RD for this vrf */
|
||||
uint16_t vrf_rd_id;
|
||||
|
29
configure.ac
@ -396,6 +396,8 @@ AC_ARG_ENABLE(rpki,
|
||||
AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
|
||||
AC_ARG_ENABLE([clippy-only],
|
||||
AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
|
||||
AC_ARG_ENABLE([numeric_version],
|
||||
AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)]))
|
||||
|
||||
AS_IF([test "${enable_clippy_only}" != "yes"], [
|
||||
AC_CHECK_HEADERS(json-c/json.h)
|
||||
@ -647,6 +649,14 @@ AC_DEFINE_UNQUOTED(MULTIPATH_NUM, $MPATH_NUM, Maximum number of paths for a rout
|
||||
|
||||
AC_DEFINE_UNQUOTED(VTYSH_PAGER, "$VTYSH_PAGER", [What pager to use])
|
||||
|
||||
dnl ------------------------------------
|
||||
dnl Alpine only accepts numeric versions
|
||||
dnl ------------------------------------
|
||||
if test "x${enable_numeric_version}" != "x" ; then
|
||||
VERSION="`echo ${VERSION} | tr -c -d '[[.0-9]]'`"
|
||||
PACKAGE_VERSION="`echo ${PACKAGE_VERSION} | tr -c -d '[[.0-9]]'`"
|
||||
fi
|
||||
|
||||
dnl -----------------------------------
|
||||
dnl Add extra version string to package
|
||||
dnl name, string and version fields.
|
||||
@ -1872,27 +1882,10 @@ AC_CONFIG_FILES([Makefile
|
||||
redhat/frr.spec
|
||||
debianpkg/Makefile
|
||||
debianpkg/changelog
|
||||
alpine/APKBUILD
|
||||
snapcraft/snapcraft.yaml
|
||||
lib/version.h
|
||||
tests/lib/cli/test_cli.refout
|
||||
doc/defines.texi
|
||||
doc/bgpd.8
|
||||
doc/isisd.8
|
||||
doc/ospf6d.8
|
||||
doc/ospfclient.8
|
||||
doc/ospfd.8
|
||||
doc/ldpd.8
|
||||
doc/ripd.8
|
||||
doc/eigrpd.8
|
||||
doc/ripngd.8
|
||||
doc/pimd.8
|
||||
doc/mtracebis.8
|
||||
doc/nhrpd.8
|
||||
doc/vtysh.1
|
||||
doc/watchfrr.8
|
||||
doc/zebra.8
|
||||
doc/frr.1
|
||||
doc/frr-args.8
|
||||
pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
|
||||
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
|
||||
pkgsrc/eigrpd.sh])
|
||||
|
@ -27,6 +27,9 @@ MULTIPATH ?= 256
|
||||
WANT_FRR_USER ?= frr
|
||||
WANT_FRR_VTY_GROUP ?= frrvty
|
||||
|
||||
# Don't build PDF docs by default
|
||||
GENERATE_PDF ?= 0
|
||||
|
||||
#
|
||||
####################################
|
||||
|
||||
@ -135,18 +138,11 @@ override_dh_auto_configure:
|
||||
fi
|
||||
|
||||
override_dh_auto_build:
|
||||
#dh_auto_build
|
||||
$(MAKE)
|
||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
||||
|
||||
|
||||
# doc/ is a bit crazy
|
||||
ifeq ($(GENERATE_PDF), 1)
|
||||
dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf
|
||||
dh_auto_build -- -C doc pdf
|
||||
endif
|
||||
rm -vf doc/frr.info
|
||||
dh_auto_build -- -C doc frr.info
|
||||
rm -vf doc/frr.info.html*
|
||||
rm -vf doc/user/_build/texinfo/frr.info
|
||||
dh_auto_build -- -C doc info
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
@ -5,18 +5,6 @@ usr/include/frr/
|
||||
usr/lib/
|
||||
tools/frr etc/init.d/
|
||||
usr/share/doc/frr/
|
||||
usr/share/man/man1/vtysh.1
|
||||
usr/share/man/man1/frr.1
|
||||
usr/share/man/man8
|
||||
usr/share/man/man8/bgpd.8
|
||||
usr/share/man/man8/ospf6d.8
|
||||
usr/share/man/man8/ospfd.8
|
||||
usr/share/man/man8/ripd.8
|
||||
usr/share/man/man8/ripngd.8
|
||||
usr/share/man/man8/zebra.8
|
||||
usr/share/man/man8/isisd.8
|
||||
usr/share/man/man8/watchfrr.8
|
||||
usr/share/man/man8/mtracebis.8
|
||||
usr/share/snmp/mibs/
|
||||
tools/etc/* etc/
|
||||
tools/*.service lib/systemd/system
|
||||
|
@ -27,6 +27,9 @@ MULTIPATH ?= 256
|
||||
WANT_FRR_USER ?= frr
|
||||
WANT_FRR_VTY_GROUP ?= frrvty
|
||||
|
||||
# Don't build PDF docs by default
|
||||
GENERATE_PDF ?= 0
|
||||
|
||||
#
|
||||
####################################
|
||||
|
||||
@ -137,16 +140,13 @@ override_dh_auto_configure:
|
||||
override_dh_auto_build:
|
||||
#dh_auto_build
|
||||
$(MAKE)
|
||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
||||
|
||||
|
||||
# doc/ is a bit crazy
|
||||
ifeq ($(GENERATE_PDF), 1)
|
||||
dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf
|
||||
dh_auto_build -- -C doc pdf
|
||||
endif
|
||||
rm -vf doc/frr.info
|
||||
dh_auto_build -- -C doc frr.info
|
||||
rm -vf doc/frr.info.html*
|
||||
rm -vf doc/_build/texinfo/frr.info
|
||||
dh_auto_build -- -C doc info
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
@ -4,7 +4,7 @@ Priority: optional
|
||||
Maintainer: Nobody <nobody@frrouting.org>
|
||||
Uploaders: Nobody <nobody@frrouting.org>
|
||||
XSBC-Original-Maintainer: <maintainers@frrouting.org>
|
||||
Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr
|
||||
Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddr, python-sphinx
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://www.frrouting.org/
|
||||
|
||||
|
@ -2,7 +2,5 @@ AUTHORS
|
||||
NEWS
|
||||
README
|
||||
REPORTING-BUGS
|
||||
doc/BGP-TypeCode
|
||||
doc/draft-zebra-00.txt
|
||||
doc/mpls/
|
||||
bgpd/BGP4-MIB.txt
|
||||
doc/user/*.rst
|
||||
doc/figures/*.png
|
||||
|
@ -1 +1 @@
|
||||
doc/frr.info*
|
||||
doc/user/_build/texinfo/frr.info
|
||||
|
@ -1,2 +1 @@
|
||||
usr/share/info
|
||||
doc/*.png usr/share/info
|
||||
doc/user/_build/texinfo/*.png usr/share/info
|
||||
|
@ -5,20 +5,7 @@ usr/include/frr/
|
||||
usr/lib/
|
||||
tools/frr usr/lib/frr
|
||||
usr/share/doc/frr/
|
||||
usr/share/man/man1/vtysh.1
|
||||
usr/share/man/man1/frr.1
|
||||
usr/share/man/man8
|
||||
usr/share/man/man8/bgpd.8
|
||||
usr/share/man/man8/ospf6d.8
|
||||
usr/share/man/man8/ospfd.8
|
||||
usr/share/man/man8/ripd.8
|
||||
usr/share/man/man8/ripngd.8
|
||||
usr/share/man/man8/zebra.8
|
||||
usr/share/man/man8/isisd.8
|
||||
usr/share/man/man8/watchfrr.8
|
||||
usr/share/man/man8/frr-args.8
|
||||
usr/share/man/man8/mtracebis.8
|
||||
usr/share/snmp/mibs/
|
||||
tools/etc/* etc/
|
||||
tools/*.service lib/systemd/system
|
||||
tools/*.service lib/systemd/system
|
||||
debian/frr.conf usr/lib/tmpfiles.d
|
||||
|
@ -1,9 +1,15 @@
|
||||
doc/bgpd.8
|
||||
doc/ospf6d.8
|
||||
doc/ospfd.8
|
||||
doc/ripd.8
|
||||
doc/ripngd.8
|
||||
doc/vtysh.1
|
||||
doc/zebra.8
|
||||
doc/isisd.8
|
||||
doc/watchfrr.8
|
||||
doc/manpages/_build/man/frr.1
|
||||
doc/manpages/_build/man/bgpd.8
|
||||
doc/manpages/_build/man/pimd.8
|
||||
doc/manpages/_build/man/eigrpd.8
|
||||
doc/manpages/_build/man/ldpd.8
|
||||
doc/manpages/_build/man/nhrpd.8
|
||||
doc/manpages/_build/man/ospf6d.8
|
||||
doc/manpages/_build/man/ospfd.8
|
||||
doc/manpages/_build/man/ripd.8
|
||||
doc/manpages/_build/man/ripngd.8
|
||||
doc/manpages/_build/man/vtysh.1
|
||||
doc/manpages/_build/man/zebra.8
|
||||
doc/manpages/_build/man/isisd.8
|
||||
doc/manpages/_build/man/watchfrr.8
|
||||
doc/manpages/_build/man/mtracebis.8
|
||||
|
@ -27,6 +27,9 @@ MULTIPATH ?= 256
|
||||
WANT_FRR_USER ?= frr
|
||||
WANT_FRR_VTY_GROUP ?= frrvty
|
||||
|
||||
# Don't build PDF docs by default
|
||||
GENERATE_PDF ?= 0
|
||||
|
||||
#
|
||||
####################################
|
||||
|
||||
@ -136,18 +139,12 @@ override_dh_auto_configure:
|
||||
fi
|
||||
|
||||
override_dh_auto_build:
|
||||
#dh_auto_build
|
||||
$(MAKE)
|
||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
||||
|
||||
|
||||
# doc/ is a bit crazy
|
||||
ifeq ($(GENERATE_PDF), 1)
|
||||
dh_auto_build -- -C doc frr.pdf || true # pdfetex fails with exit code 1 but still produces a good looking .pdf
|
||||
dh_auto_build -- -C doc pdf
|
||||
endif
|
||||
rm -vf doc/frr.info
|
||||
dh_auto_build -- -C doc frr.info
|
||||
rm -vf doc/frr.info.html*
|
||||
rm -vf doc/user/_build/texinfo/frr.info
|
||||
dh_auto_build -- -C doc info
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
9
doc/.gitignore
vendored
@ -2,13 +2,6 @@ Makefile
|
||||
Makefile.in
|
||||
mdate-sh
|
||||
draft-zebra-00.txt
|
||||
frr.info-*
|
||||
zebra.html
|
||||
defines.texi
|
||||
version.texi
|
||||
texinfo.tex
|
||||
frr.html
|
||||
frr.info
|
||||
*.pdf
|
||||
*.eps
|
||||
frr.ps
|
||||
@ -28,8 +21,6 @@ stamp-vti
|
||||
*.toc
|
||||
*.tp
|
||||
*.vr
|
||||
*.8
|
||||
*.1
|
||||
.arch-inventory
|
||||
.arch-ids
|
||||
*~
|
||||
|
@ -1,96 +0,0 @@
|
||||
Building FRR for OpenWRT/LEDE from Git Source
|
||||
===============================================
|
||||
|
||||
- for the moment because of cross compile problems, master is not supported,
|
||||
only upto 3.0
|
||||
- LDP can't be built because of missing Perl-XML-LibXML in OpenWRT/LEDE tree
|
||||
|
||||
Prepare build environment
|
||||
-------------------------
|
||||
|
||||
https://lede-project.org/docs/guide-developer/install-buildsystem
|
||||
|
||||
for
|
||||
|
||||
Ubuntu 12.04LTS:
|
||||
|
||||
sudo apt-get install build-essential subversion git-core \
|
||||
libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc \
|
||||
libxml-parser-perl mercurial bzr ecj cvs unzip
|
||||
|
||||
Ubuntu 64bit:
|
||||
|
||||
sudo apt-get install build-essential subversion libncurses5-dev zlib1g-dev \
|
||||
gawk gcc-multilib flex git-core gettext libssl-dev
|
||||
|
||||
Debian 8 Jessie:
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext unzip zlib1g-dev file python
|
||||
|
||||
Debian 9 Stretch:
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext zlib1g-dev
|
||||
|
||||
Centos x86-64 (some packages require EPEL):
|
||||
|
||||
yum install subversion binutils bzip2 gcc gcc-c++ gawk gettext flex \
|
||||
ncurses-devel zlib-devel zlib-static make patch unzip glibc glibc-devel \
|
||||
perl-ExtUtils-MakeMaker glibc-static quilt ncurses-libs sed sdcc bison \
|
||||
intltool sharutils wget git-core openssl-devel xz
|
||||
|
||||
Fedora 24 - 64Bit:
|
||||
|
||||
dnf install -y subversion binutils bzip2 gcc gcc-c++ gawk gettext git-core \
|
||||
unzip ncurses-devel ncurses-compat-libs zlib-devel zlib-static make \
|
||||
flex patch perl-ExtUtils-MakeMaker perl-Thread-Queue glibc glibc-devel \
|
||||
glibc-static quilt sed sdcc intltool sharutils bison wget openssl-devel
|
||||
|
||||
|
||||
Get LEDE Sources (from Git)
|
||||
---------------------------
|
||||
|
||||
LEDE and OpenWRT is planned to remerge and won't cover the similar OpenWRT build
|
||||
As normal user:
|
||||
git clone https://git.lede-project.org/source.git lede
|
||||
cd lede
|
||||
./scripts/feeds update -a
|
||||
./scripts/feeds install -a
|
||||
cd feeds/routing
|
||||
git pull origin pull/319/head
|
||||
ln -s ../../../feeds/routing/frr/ ../../package/feeds/routing/
|
||||
cd ../..
|
||||
make menuconfig
|
||||
|
||||
Select the needed target then select needed packages in
|
||||
Network -> Routing and Redirection -> frr, exit and save
|
||||
|
||||
make or make package/frr/compile
|
||||
|
||||
It may be possible that on first build `make package/frr/compile` not to work
|
||||
and it may be needed to run a `make` for the entire build envronment, add V=s
|
||||
for debugging
|
||||
|
||||
Work with sources
|
||||
-----------------
|
||||
|
||||
To update the rc1 version or add other options, the Makefile is found in
|
||||
feeds/routing/frr
|
||||
|
||||
edit:
|
||||
PKG_VERSION:=
|
||||
PKG_SOURCE_VERSION:=<git-hash>
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Edit `/usr/sbin/frr.init` and add/remove the daemons name in section DAEMONS=
|
||||
or don't install unneded packages
|
||||
For example: zebra bgpd ldpd isisd nhrpd ospfd ospf6d pimd ripd ripngd
|
||||
|
||||
### Enable the serivce
|
||||
- service frr enable
|
||||
|
||||
### Start the service
|
||||
- service frr start
|
346
doc/Makefile.am
@ -1,194 +1,258 @@
|
||||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
# Dia, the version i have at least, doesn't do very good EPS output
|
||||
# (some of the text is scaled strangely). So this will work, but
|
||||
# it is probably better to use something like gimp to convert the
|
||||
# dia exported PNG files to EPS manually.
|
||||
# Pass down make invocation to each subdirectory.
|
||||
#
|
||||
# Here we use 'convert' from the well known 'ImageMagick' package
|
||||
# to do conversion from png to eps/pdf for figures.
|
||||
# PDF form is required for frr.pdf, using PDFTex at least.
|
||||
# Each of these directories contains a Sphinx-generated Makefile that has been
|
||||
# modified to implement all the targets required by Automake, as documented in
|
||||
# the 'Third-Party Makefiles' section of the Automake docs.
|
||||
#
|
||||
# TeX implementation, which we depend on already anyway.
|
||||
#
|
||||
# dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf
|
||||
SUFFIXES = .png .eps .dia .pdf
|
||||
DIATOPNG = dia -t png -e
|
||||
DIATOEPS = dia -t eps -e
|
||||
PNGTOEPS = convert -antialias -contrast -despeckle
|
||||
PNGTOPDF = $(PNGTOEPS)
|
||||
EPSTOPDF = epstopdf
|
||||
# Note the absence of the 'developer' directory here; development docs are
|
||||
# never built as part of a regular build. They are only built when explicitly
|
||||
# asked for. See comment further down.
|
||||
|
||||
VNCFIGURES_PNG =
|
||||
VNCFIGURES_DIA = -vnc-mesh -vnc-frr-route-reflector \
|
||||
-vnc-commercial-route-reflector -vnc-redundant-route-reflectors \
|
||||
-vnc-gw -vnc-gw-rr
|
||||
# Sphinx is not designed to be invoked multiple times against the same toctree.
|
||||
.NOTPARALLEL:
|
||||
|
||||
# TODO: A target that creates an empty text file for each member of
|
||||
# VNCFIGURES_TXT
|
||||
VNCFIGURES_TXT = $(VNCFIGURES:%.png=%.txt)
|
||||
SUBDIRS = manpages user
|
||||
AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir} doczdir=${abs_srcdir}
|
||||
|
||||
# The figure sources
|
||||
figures_names_parts = -normal-processing -rs-processing \
|
||||
_topologies_full _topologies_rs \
|
||||
$(VNCFIGURES_DIA)
|
||||
MANPAGE_BUILDDIR = manpages/_build/man
|
||||
|
||||
figures_sources = $(figures_names_parts:%=fig%.dia)
|
||||
figures_png = $(figures_names_parts:%=fig%.png) $(VNCFIGURES_PNG)
|
||||
figures_pdf = $(figures_names_parts:%=fig%.pdf) $(VNCFIGURES_PNG:%.png=%.pdf)
|
||||
figures_eps = $(figures_names_parts:%=fig%.eps) $(VNCFIGURES_PNG:%.png=%.eps)
|
||||
figures_txt = $(figures_names_parts:%=fig%.txt)
|
||||
|
||||
# rather twisted logic because we have to build PDFs of the EPS figures for
|
||||
# PDFTex and yet build one PDF, frr.pdf, from texi source. Which means we
|
||||
# cant rely on a single automatic rule for *.pdf, eg the one automatically
|
||||
# provided by automake. If you are an automake wizard, please feel free to
|
||||
# compact it somehow.
|
||||
|
||||
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) defines.texi
|
||||
$(TEXI2PDF) -o "$@" $< || true
|
||||
|
||||
# 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 \
|
||||
babeld.texi \
|
||||
install.texi \
|
||||
ipv6.texi \
|
||||
kernel.texi \
|
||||
main.texi \
|
||||
nhrpd.texi \
|
||||
eigrpd.texi \
|
||||
ospf6d.texi \
|
||||
ospfd.texi \
|
||||
overview.texi \
|
||||
protocol.texi \
|
||||
ripd.texi \
|
||||
ripngd.texi \
|
||||
routemap.texi \
|
||||
snmp.texi \
|
||||
vtysh.texi \
|
||||
routeserver.texi \
|
||||
$(figures_png) \
|
||||
snmptrap.texi \
|
||||
ospf_fundamentals.texi \
|
||||
isisd.texi $(figures_txt) \
|
||||
rpki.texi \
|
||||
pimd.texi \
|
||||
#END
|
||||
|
||||
.png.eps:
|
||||
$(PNGTOEPS) $< "$@"
|
||||
|
||||
.png.pdf:
|
||||
$(PNGTOPDF) $< "$@"
|
||||
|
||||
.dia.png:
|
||||
$(DIATOPNG) "$@" $<
|
||||
|
||||
man_MANS = frr.1 frr-args.8
|
||||
# This is a hack, see comment further down.
|
||||
man_MANS = $(MANPAGE_BUILDDIR)/frr.1
|
||||
|
||||
if PIMD
|
||||
man_MANS += pimd.8
|
||||
man_MANS += mtracebis.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/pimd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/mtracebis.8
|
||||
endif
|
||||
|
||||
if BGPD
|
||||
man_MANS += bgpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/bgpd.8
|
||||
endif
|
||||
|
||||
if ISISD
|
||||
man_MANS += isisd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/isisd.8
|
||||
endif
|
||||
|
||||
if OSPF6D
|
||||
man_MANS += ospf6d.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ospf6d.8
|
||||
endif
|
||||
|
||||
if OSPFCLIENT
|
||||
man_MANS += ospfclient.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ospfclient.8
|
||||
endif
|
||||
|
||||
if OSPFD
|
||||
man_MANS += ospfd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ospfd.8
|
||||
endif
|
||||
|
||||
if LDPD
|
||||
man_MANS += ldpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ldpd.8
|
||||
endif
|
||||
|
||||
if RIPD
|
||||
man_MANS += ripd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ripd.8
|
||||
endif
|
||||
|
||||
if RIPNGD
|
||||
man_MANS += ripngd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/ripngd.8
|
||||
endif
|
||||
|
||||
if NHRPD
|
||||
man_MANS += nhrpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/nhrpd.8
|
||||
endif
|
||||
|
||||
if VTYSH
|
||||
man_MANS += vtysh.1
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/vtysh.1
|
||||
endif
|
||||
|
||||
if WATCHFRR
|
||||
man_MANS += watchfrr.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/watchfrr.8
|
||||
endif
|
||||
|
||||
if ZEBRA
|
||||
man_MANS += zebra.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/zebra.8
|
||||
endif
|
||||
|
||||
if EIGRPD
|
||||
man_MANS += eigrpd.8
|
||||
man_MANS += $(MANPAGE_BUILDDIR)/eigrpd.8
|
||||
endif
|
||||
|
||||
EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
|
||||
\
|
||||
bgpd.8.in \
|
||||
isisd.8.in \
|
||||
ospf6d.8.in \
|
||||
ospfclient.8.in \
|
||||
ospfd.8.in \
|
||||
ldpd.8.in \
|
||||
ripd.8.in \
|
||||
ripngd.8.in \
|
||||
pimd.8.in \
|
||||
mtracebis.8.in \
|
||||
nhrpd.8.in \
|
||||
vtysh.1.in \
|
||||
watchfrr.8.in \
|
||||
zebra.8.in \
|
||||
frr.1.in \
|
||||
eigrpd.8.in \
|
||||
\
|
||||
mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \
|
||||
mpls/opaque_lsa.txt mpls/ospfd.conf \
|
||||
$(figures_sources) $(figures_png) $(figures_txt)
|
||||
# Automake is particular about manpages. It is aware of them and has some
|
||||
# special facilities for handling them, but it assumes that manpages are always
|
||||
# given in groff source and so these facilities are limited to simply
|
||||
# specifying the path to the groff sources in a special variable. There is no
|
||||
# target for building manpages that can be extended, as there are for pdf,
|
||||
# html, dvi, etc. Unfortunately this leaves us with hijacking the
|
||||
# 'install-data' and 'all' targets in the 3rd-party Makefile in manpages/ to
|
||||
# make sure manpages are always built, and then using the special Automake
|
||||
# variable defined above in order to take advantage of automatic installation.
|
||||
#
|
||||
# However, it is conceivable that someone may want to build just the manpages,
|
||||
# so here's an explicit target for that.
|
||||
man:
|
||||
$(MAKE) -C manpages man
|
||||
|
||||
draft-zebra-00.txt: draft-zebra-00.ms
|
||||
groff -T ascii -ms $< > $@
|
||||
# Automake automatically defines targets for various document formats. All of
|
||||
# the child 3rd-party Makefiles are aware of all Automake targets and implement
|
||||
# the ones we are interested in.
|
||||
#
|
||||
# The SUBDIRS variable at the top of this Makefile.am causes the following
|
||||
# implicit Automake targets to only build user documentation, and not developer
|
||||
# documentation:
|
||||
# - info
|
||||
# - html
|
||||
# - pdf
|
||||
#
|
||||
# If you wish to build developer documentation, use these targets:
|
||||
developer-info:
|
||||
$(MAKE) -C developer info
|
||||
|
||||
# Ensure that all of the figures are copied into the html directory
|
||||
html-local: $(HTMLS)
|
||||
if test -d $(HTMLS) ; then \
|
||||
cp -p $(figures_png) $(HTMLS) ; \
|
||||
else \
|
||||
echo "$(HTMLS) is not a directory. Make it so, the rerun make."; \
|
||||
fi
|
||||
developer-pdf:
|
||||
$(MAKE) -C developer latexpdf
|
||||
|
||||
developer-html:
|
||||
$(MAKE) -C developer html
|
||||
|
||||
# If you want to build the developer's docs in other formats, try the
|
||||
# following:
|
||||
#
|
||||
# $ cd developer
|
||||
# $ make help
|
||||
|
||||
# dist tarballs want doc sources
|
||||
EXTRA_DIST = frr-sphinx.mk \
|
||||
manpages/defines.rst \
|
||||
manpages/ldpd.rst \
|
||||
manpages/index.rst \
|
||||
manpages/bgpd.rst \
|
||||
manpages/watchfrr.rst \
|
||||
manpages/ospfclient.rst \
|
||||
manpages/ripd.rst \
|
||||
manpages/zebra.rst \
|
||||
manpages/epilogue.rst \
|
||||
manpages/eigrpd.rst \
|
||||
manpages/isisd.rst \
|
||||
manpages/ospf6d.rst \
|
||||
manpages/common-options.rst \
|
||||
manpages/ospfd.rst \
|
||||
manpages/vtysh.rst \
|
||||
manpages/nhrpd.rst \
|
||||
manpages/pimd.rst \
|
||||
manpages/mtracebis.rst \
|
||||
manpages/ripngd.rst \
|
||||
manpages/frr.rst \
|
||||
manpages/conf.py \
|
||||
manpages/Makefile \
|
||||
developer/Building_FRR_on_NetBSD7.rst \
|
||||
developer/ldpd-basic-test-setup.md \
|
||||
developer/cli.rst \
|
||||
developer/index.rst \
|
||||
developer/library.rst \
|
||||
developer/memtypes.rst \
|
||||
developer/bgpd.rst \
|
||||
developer/draft-zebra-00.ms \
|
||||
developer/dev-modules.md \
|
||||
developer/conf.py \
|
||||
developer/next-hop-tracking.rst \
|
||||
developer/Building_FRR_on_FreeBSD11.rst \
|
||||
developer/building.rst \
|
||||
developer/Building_FRR_on_CentOS6.rst \
|
||||
developer/Building_FRR_on_Ubuntu1604.rst \
|
||||
developer/ospf-api.rst \
|
||||
developer/ospf-sr.rst \
|
||||
developer/Building_FRR_on_OpenBSD6.rst \
|
||||
developer/Building_FRR_on_Debian8.rst \
|
||||
developer/Building_FRR_on_NetBSD6.rst \
|
||||
developer/Building_FRR_on_Debian9.rst \
|
||||
developer/Building_FRR_on_LEDE-OpenWRT.rst \
|
||||
developer/modules.rst \
|
||||
developer/Building_FRR_on_FreeBSD10.rst \
|
||||
developer/Building_FRR_on_Ubuntu1204.rst \
|
||||
developer/Building_FRR_on_Fedora24.rst \
|
||||
developer/Makefile \
|
||||
developer/Building_FRR_on_FreeBSD9.rst \
|
||||
developer/BGP-TypeCode \
|
||||
developer/Building_FRR_on_OmniOS.rst \
|
||||
developer/Building_FRR_on_CentOS7.rst \
|
||||
developer/hooks.rst \
|
||||
developer/OSPF-API.md \
|
||||
developer/workflow.rst \
|
||||
developer/Building_FRR_on_Ubuntu1404.rst \
|
||||
user/ospf_fundamentals.rst \
|
||||
user/routemap.rst \
|
||||
user/index.rst \
|
||||
user/conf.py \
|
||||
user/ipv6.rst \
|
||||
user/ripd.rst \
|
||||
user/vnc.rst \
|
||||
user/zebra.rst \
|
||||
user/installation.rst \
|
||||
user/overview.rst \
|
||||
user/protocol.rst \
|
||||
user/eigrpd.rst \
|
||||
user/rpki.rst \
|
||||
user/kernel.rst \
|
||||
user/isisd.rst \
|
||||
user/ospf6d.rst \
|
||||
user/Useful_Sysctl_Settings.md \
|
||||
user/basic.rst \
|
||||
user/ospfd.rst \
|
||||
user/vtysh.rst \
|
||||
user/filter.rst \
|
||||
user/nhrpd.rst \
|
||||
user/Makefile \
|
||||
user/routeserver.rst \
|
||||
user/appendix.rst \
|
||||
user/bgp.rst \
|
||||
user/babeld.rst \
|
||||
user/snmp.rst \
|
||||
user/pim.rst \
|
||||
user/ripngd.rst \
|
||||
user/snmptrap.rst \
|
||||
user/glossary.rst \
|
||||
mpls/ChangeLog.opaque.txt \
|
||||
mpls/ospfd.conf \
|
||||
mpls/cli_summary.txt \
|
||||
mpls/opaque_lsa.txt \
|
||||
figures/frr-logo.png \
|
||||
figures/fig-vnc-commercial-route-reflector.dia \
|
||||
figures/ospf_api_msghdr.png \
|
||||
figures/fig-normal-processing.txt \
|
||||
figures/fig-vnc-gw-rr.txt \
|
||||
figures/fig-vnc-mesh.dia \
|
||||
figures/frr-logo-medium.png \
|
||||
figures/git_branches.svg \
|
||||
figures/fig-vnc-commercial-route-reflector.txt \
|
||||
figures/fig_topologies_rs.txt \
|
||||
figures/git_branches.png \
|
||||
figures/fig-vnc-mesh.txt \
|
||||
figures/ospf_api_msgs1.png \
|
||||
figures/fig-vnc-redundant-route-reflectors.txt \
|
||||
figures/fig-vnc-commercial-route-reflector.png \
|
||||
figures/fig-vnc-gw.png \
|
||||
figures/fig_topologies_rs.png \
|
||||
figures/fig_topologies_full.txt \
|
||||
figures/fig-vnc-frr-route-reflector.txt \
|
||||
figures/fig-normal-processing.dia \
|
||||
figures/fig-vnc-redundant-route-reflectors.png \
|
||||
figures/fig-vnc-frr-route-reflector.dia \
|
||||
figures/fig_topologies_full.png \
|
||||
figures/fig-vnc-redundant-route-reflectors.dia \
|
||||
figures/fig-normal-processing.png \
|
||||
figures/fig-rs-processing.dia \
|
||||
figures/ospf_api_msgs2.png \
|
||||
figures/fig-vnc-gw.dia \
|
||||
figures/fig-rs-processing.txt \
|
||||
figures/frr-logo-icon.png \
|
||||
figures/ospf_api_architecture.png \
|
||||
figures/fig-vnc-gw.txt \
|
||||
figures/fig-rs-processing.png \
|
||||
figures/frr-icon.svg \
|
||||
figures/fig_topologies_rs.dia \
|
||||
figures/fig-vnc-frr-route-reflector.png \
|
||||
figures/fig-vnc-gw-rr.png \
|
||||
figures/fig-vnc-gw-rr.dia \
|
||||
figures/fig_topologies_full.dia \
|
||||
figures/frr-logo-small.png \
|
||||
figures/fig-vnc-mesh.png
|
||||
|
@ -1,257 +0,0 @@
|
||||
@node Packet Binary Dump Format
|
||||
@appendix Packet Binary Dump Format
|
||||
|
||||
FRR can dump routing protocol packet into file with a binary format
|
||||
(@pxref{Dump BGP packets and table}).
|
||||
|
||||
It seems to be better that we share the MRT's header format for
|
||||
backward compatibility with MRT's dump logs. We should also define the
|
||||
binary format excluding the header, because we must support both IP
|
||||
v4 and v6 addresses as socket addresses and / or routing entries.
|
||||
|
||||
In the last meeting, we discussed to have a version field in the
|
||||
header. But Masaki told us that we can define new `type' value rather
|
||||
than having a `version' field, and it seems to be better because we
|
||||
don't need to change header format.
|
||||
|
||||
Here is the common header format. This is same as that of MRT.
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Subtype |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP_ET, the common header format will
|
||||
contain an additional microsecond field (RFC6396 2011).
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Subtype |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Microsecond |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and
|
||||
Address Family == IP (version 4)
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Old State | New State |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Where State is the value defined in RFC1771.
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE,
|
||||
and Address Family == IP version 6
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Old State | New State |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE,
|
||||
and Address Family == IP (version 4)
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Message Packet |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Where BGP Message Packet is the whole contents of the
|
||||
BGP4 message including header portion.
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE,
|
||||
and Address Family == IP version 6
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source AS number | Destination AS number |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Interface Index | Address Family |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Destination IP address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Message Packet |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY,
|
||||
and Address Family == IP (version 4)
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| View # | Status |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time Last Change |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Address Family | SAFI | Next-Hop-Len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix Length | Address Prefix [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Attribute Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Attribute [variable length] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY,
|
||||
and Address Family == IP version 6
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| View # | Status |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Time Last Change |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Address Family | SAFI | Next-Hop-Len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Next Hop Address (Cont'd) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix Length | Address Prefix [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Address Prefix (cont'd) [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Attribute Length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BGP Attribute [variable length] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
BGP4 Attribute must not contain MP_UNREACH_NLRI.
|
||||
If BGP Attribute has MP_REACH_NLRI field, it must has
|
||||
zero length NLRI, e.g., MP_REACH_NLRI has only Address
|
||||
Family, SAFI and next-hop values.
|
||||
|
||||
If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT,
|
||||
|
||||
@example
|
||||
@group
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| View # | File Name [variable] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The file specified in "File Name" contains all routing entries,
|
||||
which are in the format of ``subtype == BGP4MP_ENTRY''.
|
||||
|
||||
@example
|
||||
@group
|
||||
Constants:
|
||||
/* type value */
|
||||
#define MSG_PROTOCOL_BGP4MP 16
|
||||
#define MSG_PROTOCOL_BGP4MP_ET 17
|
||||
/* subtype value */
|
||||
#define BGP4MP_STATE_CHANGE 0
|
||||
#define BGP4MP_MESSAGE 1
|
||||
#define BGP4MP_ENTRY 2
|
||||
#define BGP4MP_SNAPSHOT 3
|
||||
@end group
|
||||
@end example
|
212
doc/babeld.texi
@ -1,212 +0,0 @@
|
||||
@c -*-texinfo-*-
|
||||
@c This is part of the FRR Manual.
|
||||
@c @value{COPYRIGHT_STR}
|
||||
@c See file frr.texi for copying conditions.
|
||||
@node Babel
|
||||
@chapter Babel
|
||||
|
||||
Babel is an interior gateway protocol that is suitable both for wired
|
||||
networks and for wireless mesh networks. Babel has been described as
|
||||
``RIP on speed'' --- it is based on the same principles as RIP, but
|
||||
includes a number of refinements that make it react much faster to
|
||||
topology changes without ever counting to infinity, and allow it to
|
||||
perform reliable link quality estimation on wireless links. Babel is
|
||||
a double-stack routing protocol, meaning that a single Babel instance
|
||||
is able to perform routing for both IPv4 and IPv6.
|
||||
|
||||
FRR implements Babel as described in RFC6126.
|
||||
|
||||
@menu
|
||||
* Configuring babeld::
|
||||
* Babel configuration::
|
||||
* Babel redistribution::
|
||||
* Show Babel information::
|
||||
* Babel debugging commands::
|
||||
@end menu
|
||||
|
||||
@node Configuring babeld, Babel configuration, Babel, Babel
|
||||
@section Configuring babeld
|
||||
|
||||
The @command{babeld} daemon can be invoked with any of the common
|
||||
options (@pxref{Common Invocation Options}).
|
||||
|
||||
The @command{zebra} daemon must be running before @command{babeld} is
|
||||
invoked. Also, if @command{zebra} is restarted then @command{babeld}
|
||||
must be too.
|
||||
|
||||
Configuration of @command{babeld} is done in its configuration file
|
||||
@file{babeld.conf}.
|
||||
|
||||
@node Babel configuration, Babel redistribution, Configuring babeld, Babel
|
||||
@section Babel configuration
|
||||
|
||||
@deffn Command {router babel} {}
|
||||
@deffnx Command {no router babel} {}
|
||||
Enable or disable Babel routing.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {babel resend-delay <20-655340>} {}
|
||||
Specifies the time after which important messages are resent when
|
||||
avoiding a black-hole. The default is 2000@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {babel diversity} {}
|
||||
@deffnx Command {no babel diversity} {}
|
||||
Enable or disable routing using radio frequency diversity. This is
|
||||
highly recommended in networks with many wireless nodes.
|
||||
|
||||
If you enable this, you will probably want to set @code{babel
|
||||
diversity-factor} and @code{babel channel} below.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {babel diversity-factor <1-256>} {}
|
||||
Sets the multiplicative factor used for diversity routing, in units of
|
||||
1/256; lower values cause diversity to play a more important role in
|
||||
route selection. The default it 256, which means that diversity plays
|
||||
no role in route selection; you will probably want to set that to 128
|
||||
or less on nodes with multiple independent radios.
|
||||
@end deffn
|
||||
|
||||
@deffn {Babel Command} {network @var{ifname}} {}
|
||||
@deffnx {Babel Command} {no network @var{ifname}} {}
|
||||
Enable or disable Babel on the given interface.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel wired} {}
|
||||
@deffnx {Interface Command} {babel wireless} {}
|
||||
Specifies whether this interface is wireless, which disables a number
|
||||
of optimisations that are only correct on wired interfaces.
|
||||
Specifying @code{wireless} (the default) is always correct, but may
|
||||
cause slower convergence and extra routing traffic.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel split-horizon}
|
||||
@deffnx {Interface Command} {no babel split-horizon}
|
||||
Specifies whether to perform split-horizon on the interface.
|
||||
Specifying @code{no babel split-horizon} is always correct, while
|
||||
@code{babel split-horizon} is an optimisation that should only be used
|
||||
on symmetric and transitive (wired) networks. The default is
|
||||
@code{babel split-horizon} on wired interfaces, and @code{no babel
|
||||
split-horizon} on wireless interfaces. This flag is reset when the
|
||||
wired/wireless status of an interface is changed.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel hello-interval <20-655340>}
|
||||
Specifies the time in milliseconds between two scheduled hellos. On
|
||||
wired links, Babel notices a link failure within two hello intervals;
|
||||
on wireless links, the link quality value is reestimated at every
|
||||
hello interval. The default is 4000@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel update-interval <20-655340>}
|
||||
Specifies the time in milliseconds between two scheduled updates.
|
||||
Since Babel makes extensive use of triggered updates, this can be set
|
||||
to fairly high values on links with little packet loss. The default
|
||||
is 20000@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel channel <1-254>}
|
||||
@deffnx {Interface Command} {babel channel interfering}
|
||||
@deffnx {Interface Command} {babel channel noninterfering}
|
||||
Set the channel number that diversity routing uses for this interface
|
||||
(see @code{babel diversity} above). Noninterfering interfaces are
|
||||
assumed to only interfere with themselves, interfering interfaces are
|
||||
assumed to interfere with all other channels except noninterfering
|
||||
channels, and interfaces with a channel number interfere with
|
||||
interfering interfaces and interfaces with the same channel number.
|
||||
The default is @samp{babel channel interfering} for wireless
|
||||
interfaces, and @samp{babel channel noninterfering} for wired
|
||||
interfaces. This is reset when the wired/wireless status of an
|
||||
interface is changed.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rxcost <1-65534>}
|
||||
Specifies the base receive cost for this interface. For wireless
|
||||
interfaces, it specifies the multiplier used for computing the ETX
|
||||
reception cost (default 256); for wired interfaces, it specifies the
|
||||
cost that will be advertised to neighbours. This value is reset when
|
||||
the wired/wireless attribute of the interface is changed.
|
||||
|
||||
Do not use this command unless you know what you are doing; in most
|
||||
networks, acting directly on the cost using route maps is a better
|
||||
technique.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rtt-decay <1-256>}
|
||||
This specifies the decay factor for the exponential moving average of
|
||||
RTT samples, in units of 1/256. Higher values discard old samples
|
||||
faster. The default is 42.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rtt-min <1-65535>}
|
||||
This specifies the minimum RTT, in milliseconds, starting from which we
|
||||
increase the cost to a neighbour. The additional cost is linear in (rtt
|
||||
- rtt-min ). The default is 10@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel rtt-max <1-65535>}
|
||||
This specifies the maximum RTT, in milliseconds, above which we don't
|
||||
increase the cost to a neighbour. The default is 120@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel max-rtt-penalty <0-65535>}
|
||||
This specifies the maximum cost added to a neighbour because of RTT,
|
||||
i.e. when the RTT is higher or equal than rtt-max. The default is 0,
|
||||
which effectively disables the use of a RTT-based cost.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel enable-timestamps}
|
||||
@deffnx {Interface Command} {no babel enable-timestamps}
|
||||
Enable or disable sending timestamps with each Hello and IHU message in
|
||||
order to compute RTT values. The default is @code{no babel
|
||||
enable-timestamps}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Babel Command} {babel resend-delay <20-655340>}
|
||||
Specifies the time in milliseconds after which an ``important''
|
||||
request or update will be resent. The default is 2000@dmn{ms}. You
|
||||
probably don't want to tweak this value.
|
||||
@end deffn
|
||||
|
||||
@deffn {Babel Command} {babel smoothing-half-life <0-65534>}
|
||||
Specifies the time constant, in seconds, of the smoothing algorithm
|
||||
used for implementing hysteresis. Larger values reduce route
|
||||
oscillation at the cost of very slightly increasing convergence time.
|
||||
The value 0 disables hysteresis, and is suitable for wired networks.
|
||||
The default is 4@dmn{s}.
|
||||
@end deffn
|
||||
|
||||
@node Babel redistribution, Show Babel information, Babel configuration, Babel
|
||||
@section Babel redistribution
|
||||
|
||||
@deffn {Babel command} {redistribute @var{<ipv4|ipv6>} @var{kind}}
|
||||
@deffnx {Babel command} {no redistribute @var{<ipv4|ipv6>} @var{kind}}
|
||||
Specify which kind of routes should be redistributed into Babel.
|
||||
@end deffn
|
||||
|
||||
@node Show Babel information, Babel debugging commands, Babel redistribution, Babel
|
||||
@section Show Babel information
|
||||
|
||||
@deffn {Command} {show babel route} {}
|
||||
@deffnx {Command} {show babel route A.B.C.D}
|
||||
@deffnx {Command} {show babel route X:X::X:X}
|
||||
@deffnx {Command} {show babel route A.B.C.D/M}
|
||||
@deffnx {Command} {show babel route X:X::X:X/M}
|
||||
@deffnx {Command} {show babel interface} {}
|
||||
@deffnx {Command} {show babel interface @var{ifname}} {}
|
||||
@deffnx {Command} {show babel neighbor} {}
|
||||
@deffnx {Command} {show babel parameters} {}
|
||||
These commands dump various parts of @command{babeld}'s internal state.
|
||||
@end deffn
|
||||
|
||||
@node Babel debugging commands, , Show Babel information, Babel
|
||||
@section Babel debugging commands
|
||||
|
||||
@deffn {Babel Command} {debug babel @var{kind}} {}
|
||||
@deffnx {Babel Command} {no debug babel @var{kind}} {}
|
||||
Enable or disable debugging messages of a given kind. @var{kind} can
|
||||
be one of @samp{common}, @samp{kernel}, @samp{filter}, @samp{timeout},
|
||||
@samp{interface}, @samp{route} or @samp{all}. Note that if you have
|
||||
compiled with the NO_DEBUG flag, then these commands aren't available.
|
||||
@end deffn
|
||||
|
642
doc/basic.texi
@ -1,642 +0,0 @@
|
||||
@node Basic commands
|
||||
@chapter Basic commands
|
||||
|
||||
There are five routing daemons in use, and there is one manager daemon.
|
||||
These daemons may be located on separate machines from the manager
|
||||
daemon. Each of these daemons will listen on a particular port for
|
||||
incoming VTY connections. The routing daemons are:
|
||||
|
||||
@itemize @bullet
|
||||
@item @command{ripd}, @command{ripngd}, @command{ospfd}, @command{ospf6d}, @command{bgpd}
|
||||
@item @command{zebra}
|
||||
@end itemize
|
||||
|
||||
The following sections discuss commands common to all the routing
|
||||
daemons.
|
||||
|
||||
@menu
|
||||
* Config Commands:: Commands used in config files
|
||||
* Terminal Mode Commands:: Common commands used in a VTY
|
||||
* Common Invocation Options:: Starting the daemons
|
||||
* Loadable Module Support:: Using extension modules
|
||||
* Virtual Terminal Interfaces:: Interacting with the daemons
|
||||
@end menu
|
||||
|
||||
|
||||
|
||||
@node Config Commands
|
||||
@section Config Commands
|
||||
|
||||
@cindex Configuration files for running the software
|
||||
@c A -not configuration files for installing the software
|
||||
@cindex Files for running configurations
|
||||
@cindex Modifying the herd's behavior
|
||||
@cindex Getting the herd running
|
||||
|
||||
|
||||
@menu
|
||||
* Basic Config Commands:: Some of the generic config commands
|
||||
* Sample Config File:: An example config file
|
||||
@end menu
|
||||
|
||||
|
||||
In a config file, you can write the debugging options, a vty's password,
|
||||
routing daemon configurations, a log file name, and so forth. This
|
||||
information forms the initial command set for a routing beast as it is
|
||||
starting.
|
||||
|
||||
Config files are generally found in:
|
||||
|
||||
@itemize @w{}
|
||||
@item @file{@value{INSTALL_PREFIX_ETC}/*.conf}
|
||||
@end itemize
|
||||
|
||||
Each of the daemons has its own
|
||||
config file. For example, zebra's default config file name is:
|
||||
|
||||
@itemize @w{}
|
||||
@item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf}
|
||||
@end itemize
|
||||
|
||||
The daemon name plus @file{.conf} is the default config file name. You
|
||||
can specify a config file using the @kbd{-f} or @kbd{--config-file}
|
||||
options when starting the daemon.
|
||||
|
||||
|
||||
|
||||
@node Basic Config Commands
|
||||
@subsection Basic Config Commands
|
||||
|
||||
@deffn Command {hostname @var{hostname}} {}
|
||||
Set hostname of the router.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {password @var{password}} {}
|
||||
Set password for vty interface. If there is no password, a vty won't
|
||||
accept connections.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {enable password @var{password}} {}
|
||||
Set enable password.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log trap @var{level}} {}
|
||||
@deffnx Command {no log trap} {}
|
||||
These commands are deprecated and are present only for historical compatibility.
|
||||
The log trap command sets the current logging level for all enabled
|
||||
logging destinations, and it sets the default for all future logging commands
|
||||
that do not specify a level. The normal default
|
||||
logging level is debugging. The @code{no} form of the command resets
|
||||
the default level for future logging commands to debugging, but it does
|
||||
not change the logging level of existing logging destinations.
|
||||
@end deffn
|
||||
|
||||
|
||||
@deffn Command {log stdout} {}
|
||||
@deffnx Command {log stdout @var{level}} {}
|
||||
@deffnx Command {no log stdout} {}
|
||||
Enable logging output to stdout.
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to stdout.
|
||||
The @code{level} argument must have one of these values:
|
||||
emergencies, alerts, critical, errors, warnings, notifications, informational, or debugging. Note that the existing code logs its most important messages
|
||||
with severity @code{errors}.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log file @var{filename}} {}
|
||||
@deffnx Command {log file @var{filename} @var{level}} {}
|
||||
@deffnx Command {no log file} {}
|
||||
If you want to log into a file, please specify @code{filename} as
|
||||
in this example:
|
||||
@example
|
||||
log file /var/log/frr/bgpd.log informational
|
||||
@end example
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to a file.
|
||||
|
||||
Note: if you do not configure any file logging, and a daemon crashes due
|
||||
to a signal or an assertion failure, it will attempt to save the crash
|
||||
information in a file named /var/tmp/frr.<daemon name>.crashlog.
|
||||
For security reasons, this will not happen if the file exists already, so
|
||||
it is important to delete the file after reporting the crash information.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log syslog} {}
|
||||
@deffnx Command {log syslog @var{level}} {}
|
||||
@deffnx Command {no log syslog} {}
|
||||
Enable logging output to syslog.
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to syslog.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log monitor} {}
|
||||
@deffnx Command {log monitor @var{level}} {}
|
||||
@deffnx Command {no log monitor} {}
|
||||
Enable logging output to vty terminals that have enabled logging
|
||||
using the @code{terminal monitor} command.
|
||||
By default, monitor logging is enabled at the debugging level, but this
|
||||
command (or the deprecated @code{log trap} command) can be used to change
|
||||
the monitor logging level.
|
||||
If the optional second argument specifying the
|
||||
logging level is not present, the default logging level (typically debugging,
|
||||
but can be changed using the deprecated @code{log trap} command) will be used.
|
||||
The @code{no} form of the command disables logging to terminal monitors.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log facility @var{facility}} {}
|
||||
@deffnx Command {no log facility} {}
|
||||
This command changes the facility used in syslog messages. The default
|
||||
facility is @code{daemon}. The @code{no} form of the command resets
|
||||
the facility to the default @code{daemon} facility.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log record-priority} {}
|
||||
@deffnx Command {no log record-priority} {}
|
||||
To include the severity in all messages logged to a file, to stdout, or to
|
||||
a terminal monitor (i.e. anything except syslog),
|
||||
use the @code{log record-priority} global configuration command.
|
||||
To disable this option, use the @code{no} form of the command. By default,
|
||||
the severity level is not included in logged messages. Note: some
|
||||
versions of syslogd (including Solaris) can be configured to include
|
||||
the facility and level in the messages emitted.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log timestamp precision @var{<0-6>}} {}
|
||||
@deffnx Command {no log timestamp precision} {}
|
||||
This command sets the precision of log message timestamps to the
|
||||
given number of digits after the decimal point. Currently,
|
||||
the value must be in the range 0 to 6 (i.e. the maximum precision
|
||||
is microseconds).
|
||||
To restore the default behavior (1-second accuracy), use the
|
||||
@code{no} form of the command, or set the precision explicitly to 0.
|
||||
|
||||
@example
|
||||
@group
|
||||
log timestamp precision 3
|
||||
@end group
|
||||
@end example
|
||||
|
||||
In this example, the precision is set to provide timestamps with
|
||||
millisecond accuracy.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {log commands} {}
|
||||
This command enables the logging of all commands typed by a user to
|
||||
all enabled log destinations. The note that logging includes full
|
||||
command lines, including passwords. Once set, command logging can only
|
||||
be turned off by restarting the daemon.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {service password-encryption} {}
|
||||
Encrypt password.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {service advanced-vty} {}
|
||||
Enable advanced mode VTY.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {service terminal-length @var{<0-512>}} {}
|
||||
Set system wide line configuration. This configuration command applies
|
||||
to all VTY interfaces.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {line vty} {}
|
||||
Enter vty configuration mode.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {banner motd default} {}
|
||||
Set default motd string.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {no banner motd} {}
|
||||
No motd banner string will be printed.
|
||||
@end deffn
|
||||
|
||||
@deffn {Line Command} {exec-timeout @var{minute}} {}
|
||||
@deffnx {Line Command} {exec-timeout @var{minute} @var{second}} {}
|
||||
Set VTY connection timeout value. When only one argument is specified
|
||||
it is used for timeout value in minutes. Optional second argument is
|
||||
used for timeout value in seconds. Default timeout value is 10 minutes.
|
||||
When timeout value is zero, it means no timeout.
|
||||
@end deffn
|
||||
|
||||
@deffn {Line Command} {no exec-timeout} {}
|
||||
Do not perform timeout at all. This command is as same as
|
||||
@command{exec-timeout 0 0}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Line Command} {access-class @var{access-list}} {}
|
||||
Restrict vty connections with an access list.
|
||||
@end deffn
|
||||
|
||||
@node Sample Config File
|
||||
@subsection Sample Config File
|
||||
|
||||
|
||||
Below is a sample configuration file for the zebra daemon.
|
||||
|
||||
@example
|
||||
@group
|
||||
!
|
||||
! Zebra configuration file
|
||||
!
|
||||
hostname Router
|
||||
password zebra
|
||||
enable password zebra
|
||||
!
|
||||
log stdout
|
||||
!
|
||||
!
|
||||
@end group
|
||||
@end example
|
||||
|
||||
'!' and '#' are comment characters. If the first character of the word
|
||||
is one of the comment characters then from the rest of the line forward
|
||||
will be ignored as a comment.
|
||||
|
||||
@example
|
||||
password zebra!password
|
||||
@end example
|
||||
|
||||
If a comment character is not the first character of the word, it's a
|
||||
normal character. So in the above example '!' will not be regarded as a
|
||||
comment and the password is set to 'zebra!password'.
|
||||
|
||||
|
||||
|
||||
@node Terminal Mode Commands
|
||||
@section Terminal Mode Commands
|
||||
|
||||
@deffn Command {write terminal} {}
|
||||
Displays the current configuration to the vty interface.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {write file} {}
|
||||
Write current configuration to configuration file.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {configure terminal} {}
|
||||
Change to configuration mode. This command is the first step to
|
||||
configuration.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {terminal length @var{<0-512>}} {}
|
||||
Set terminal display length to @var{<0-512>}. If length is 0, no
|
||||
display control is performed.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {who} {}
|
||||
Show a list of currently connected vty sessions.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {list} {}
|
||||
List all available commands.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {show version} {}
|
||||
Show the current version of @value{PACKAGE_NAME} and its build host information.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {show logging} {}
|
||||
Shows the current configuration of the logging system. This includes
|
||||
the status of all logging destinations.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {logmsg @var{level} @var{message}} {}
|
||||
Send a message to all logging destinations that are enabled for messages
|
||||
of the given severity.
|
||||
@end deffn
|
||||
|
||||
|
||||
|
||||
|
||||
@node Common Invocation Options
|
||||
@section Common Invocation Options
|
||||
@c COMMON_OPTIONS
|
||||
@c OPTIONS section of the man page
|
||||
|
||||
These options apply to all @value{PACKAGE_NAME} daemons.
|
||||
|
||||
@table @samp
|
||||
|
||||
@item -d
|
||||
@itemx --daemon
|
||||
Runs in daemon mode.
|
||||
|
||||
@item -f @var{file}
|
||||
@itemx --config_file=@var{file}
|
||||
Set configuration file name.
|
||||
|
||||
@item -h
|
||||
@itemx --help
|
||||
Display this help and exit.
|
||||
|
||||
@item -i @var{file}
|
||||
@itemx --pid_file=@var{file}
|
||||
|
||||
Upon startup the process identifier of the daemon is written to a file,
|
||||
typically in @file{/var/run}. This file can be used by the init system
|
||||
to implement commands such as @command{@dots{}/init.d/zebra status},
|
||||
@command{@dots{}/init.d/zebra restart} or @command{@dots{}/init.d/zebra
|
||||
stop}.
|
||||
|
||||
The file name is an run-time option rather than a configure-time option
|
||||
so that multiple routing daemons can be run simultaneously. This is
|
||||
useful when using @value{PACKAGE_NAME} to implement a routing looking glass. One
|
||||
machine can be used to collect differing routing views from differing
|
||||
points in the network.
|
||||
|
||||
@item -A @var{address}
|
||||
@itemx --vty_addr=@var{address}
|
||||
Set the VTY local address to bind to. If set, the VTY socket will only
|
||||
be bound to this address.
|
||||
|
||||
@item -P @var{port}
|
||||
@itemx --vty_port=@var{port}
|
||||
Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not
|
||||
be opened.
|
||||
|
||||
@item -u @var{user}
|
||||
@itemx --vty_addr=@var{user}
|
||||
Set the user and group to run as.
|
||||
|
||||
@item -v
|
||||
@itemx --version
|
||||
Print program version.
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
@node Loadable Module Support
|
||||
@section Loadable Module Support
|
||||
|
||||
FRR supports loading extension modules at startup. Loading, reloading or
|
||||
unloading modules at runtime is not supported (yet). To load a module, use
|
||||
the following command line option at daemon startup:
|
||||
|
||||
@table @samp
|
||||
@item -M @var{module:options}
|
||||
@itemx --module @var{module:options}
|
||||
|
||||
Load the specified module, optionally passing options to it. If the module
|
||||
name contains a slash (/), it is assumed to be a full pathname to a file to
|
||||
be loaded. If it does not contain a slash, the
|
||||
@code{@value{INSTALL_PREFIX_MODULES}} directory is searched for a module of
|
||||
the given name; first with the daemon name prepended (e.g. @code{zebra_mod}
|
||||
for @code{mod}), then without the daemon name prepended.
|
||||
|
||||
This option is available on all daemons, though some daemons may not have
|
||||
any modules available to be loaded.
|
||||
@end table
|
||||
|
||||
|
||||
@subsection The SNMP Module
|
||||
|
||||
If SNMP is enabled during compile-time and installed as part of the package,
|
||||
the @code{snmp} module can be loaded for the @command{zebra},
|
||||
@command{bgpd}, @command{ospfd}, @command{ospf6d} and @command{ripd} daemons.
|
||||
|
||||
The module ignores any options passed to it. Refer to @ref{SNMP Support}
|
||||
for information on its usage.
|
||||
|
||||
|
||||
@subsection The FPM Module
|
||||
|
||||
If FPM is enabled during compile-time and installed as part of the package,
|
||||
the @code{fpm} module can be loaded for the @command{zebra} daemon. This
|
||||
provides the Forwarding Plane Manager ("FPM") API.
|
||||
|
||||
The module expects its argument to be either @code{netlink} or
|
||||
@code{protobuf}, specifying the encapsulation to use. @code{netlink} is the
|
||||
default, and @code{protobuf} may not be available if the module was built
|
||||
without protobuf support. Refer to @ref{zebra FIB push interface} for more
|
||||
information.
|
||||
|
||||
|
||||
@node Virtual Terminal Interfaces
|
||||
@section Virtual Terminal Interfaces
|
||||
|
||||
VTY -- Virtual Terminal [aka TeletYpe] Interface is a command line
|
||||
interface (CLI) for user interaction with the routing daemon.
|
||||
|
||||
@menu
|
||||
* VTY Overview:: Basics about VTYs
|
||||
* VTY Modes:: View, Enable, and Other VTY modes
|
||||
* VTY CLI Commands:: Commands for movement, edition, and management
|
||||
@end menu
|
||||
|
||||
|
||||
|
||||
@node VTY Overview
|
||||
@subsection VTY Overview
|
||||
|
||||
|
||||
VTY stands for Virtual TeletYpe interface. It means you can connect to
|
||||
the daemon via the telnet protocol.
|
||||
|
||||
To enable a VTY interface, you have to setup a VTY password. If there
|
||||
is no VTY password, one cannot connect to the VTY interface at all.
|
||||
|
||||
@example
|
||||
@group
|
||||
% telnet localhost 2601
|
||||
Trying 127.0.0.1...
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
|
||||
Hello, this is @value{PACKAGE_NAME} (version @value{PACKAGE_VERSION})
|
||||
@value{COPYRIGHT_STR}
|
||||
|
||||
User Access Verification
|
||||
|
||||
Password: XXXXX
|
||||
Router> ?
|
||||
enable Turn on privileged commands
|
||||
exit Exit current mode and down to previous mode
|
||||
help Description of the interactive help system
|
||||
list Print command list
|
||||
show Show running system information
|
||||
who Display who is on a vty
|
||||
Router> enable
|
||||
Password: XXXXX
|
||||
Router# configure terminal
|
||||
Router(config)# interface eth0
|
||||
Router(config-if)# ip address 10.0.0.1/8
|
||||
Router(config-if)# ^Z
|
||||
Router#
|
||||
@end group
|
||||
@end example
|
||||
|
||||
'?' is very useful for looking up commands.
|
||||
|
||||
@node VTY Modes
|
||||
@subsection VTY Modes
|
||||
|
||||
There are three basic VTY modes:
|
||||
|
||||
@menu
|
||||
* VTY View Mode:: Mode for read-only interaction
|
||||
* VTY Enable Mode:: Mode for read-write interaction
|
||||
* VTY Other Modes:: Special modes (tftp, etc)
|
||||
@end menu
|
||||
|
||||
There are commands that may be restricted to specific VTY modes.
|
||||
|
||||
@node VTY View Mode
|
||||
@subsubsection VTY View Mode
|
||||
@c to be written (gpoul)
|
||||
|
||||
|
||||
This mode is for read-only access to the CLI. One may exit the mode by
|
||||
leaving the system, or by entering @code{enable} mode.
|
||||
|
||||
@node VTY Enable Mode
|
||||
@subsubsection VTY Enable Mode
|
||||
|
||||
@c to be written (gpoul)
|
||||
This mode is for read-write access to the CLI. One may exit the mode by
|
||||
leaving the system, or by escaping to view mode.
|
||||
|
||||
@node VTY Other Modes
|
||||
@subsubsection VTY Other Modes
|
||||
|
||||
|
||||
@c to be written (gpoul)
|
||||
This page is for describing other modes.
|
||||
|
||||
@node VTY CLI Commands
|
||||
@subsection VTY CLI Commands
|
||||
|
||||
Commands that you may use at the command-line are described in the following
|
||||
three subsubsections.
|
||||
|
||||
@menu
|
||||
* CLI Movement Commands:: Commands for moving the cursor about
|
||||
* CLI Editing Commands:: Commands for changing text
|
||||
* CLI Advanced Commands:: Other commands, session management and so on
|
||||
@end menu
|
||||
|
||||
@node CLI Movement Commands
|
||||
@subsubsection CLI Movement Commands
|
||||
|
||||
These commands are used for moving the CLI cursor. The @key{C} character
|
||||
means press the Control Key.
|
||||
|
||||
@table @kbd
|
||||
|
||||
@item C-f
|
||||
@itemx @key{RIGHT}
|
||||
@kindex C-f
|
||||
@kindex @key{RIGHT}
|
||||
Move forward one character.
|
||||
|
||||
@item C-b
|
||||
@itemx @key{LEFT}
|
||||
@kindex C-b
|
||||
@kindex @key{LEFT}
|
||||
Move backward one character.
|
||||
|
||||
@item M-f
|
||||
@kindex M-f
|
||||
Move forward one word.
|
||||
|
||||
@item M-b
|
||||
@kindex M-b
|
||||
Move backward one word.
|
||||
|
||||
@item C-a
|
||||
@kindex C-a
|
||||
Move to the beginning of the line.
|
||||
|
||||
@item C-e
|
||||
@kindex C-e
|
||||
Move to the end of the line.
|
||||
|
||||
@end table
|
||||
|
||||
@node CLI Editing Commands
|
||||
@subsubsection CLI Editing Commands
|
||||
|
||||
These commands are used for editing text on a line. The @key{C}
|
||||
character means press the Control Key.
|
||||
|
||||
@table @kbd
|
||||
|
||||
@item C-h
|
||||
@itemx @key{DEL}
|
||||
@kindex C-h
|
||||
@kindex @key{DEL}
|
||||
Delete the character before point.
|
||||
|
||||
@item C-d
|
||||
@kindex C-d
|
||||
Delete the character after point.
|
||||
|
||||
@item M-d
|
||||
@kindex M-d
|
||||
Forward kill word.
|
||||
|
||||
@item C-w
|
||||
@kindex C-w
|
||||
Backward kill word.
|
||||
|
||||
@item C-k
|
||||
@kindex C-k
|
||||
Kill to the end of the line.
|
||||
|
||||
@item C-u
|
||||
@kindex C-u
|
||||
Kill line from the beginning, erasing input.
|
||||
|
||||
@item C-t
|
||||
@kindex C-t
|
||||
Transpose character.
|
||||
|
||||
@end table
|
||||
|
||||
@node CLI Advanced Commands
|
||||
@subsubsection CLI Advanced Commands
|
||||
|
||||
There are several additional CLI commands for command line completions,
|
||||
insta-help, and VTY session management.
|
||||
|
||||
@table @kbd
|
||||
|
||||
@item C-c
|
||||
@kindex C-c
|
||||
Interrupt current input and moves to the next line.
|
||||
|
||||
@item C-z
|
||||
@kindex C-z
|
||||
End current configuration session and move to top node.
|
||||
|
||||
|
||||
@item C-n
|
||||
@itemx @key{DOWN}
|
||||
@kindex C-n
|
||||
@kindex @key{DOWN}
|
||||
Move down to next line in the history buffer.
|
||||
|
||||
@item C-p
|
||||
@itemx @key{UP}
|
||||
@kindex C-p
|
||||
@kindex @key{UP}
|
||||
Move up to previous line in the history buffer.
|
||||
|
||||
@item TAB
|
||||
@kindex @key{TAB}
|
||||
Use command line completion by typing @key{TAB}.
|
||||
|
||||
@item ?
|
||||
@kindex @key{?}
|
||||
You can use command line help by typing @code{help} at the beginning of
|
||||
the line. Typing @kbd{?} at any point in the line will show possible
|
||||
completions.
|
||||
|
||||
@end table
|
132
doc/bgpd.8.in
@ -1,132 +0,0 @@
|
||||
.TH BGPD 8 "25 November 2004" "@PACKAGE_FULLNAME@ BGPD daemon" "Version @PACKAGE_VERSION@"
|
||||
.SH NAME
|
||||
bgpd \- a BGPv4, BGPv4\+, BGPv4\- routing engine for use with @PACKAGE_FULLNAME@.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B bgpd
|
||||
[
|
||||
.B \-dhrSv
|
||||
] [
|
||||
.B \-f
|
||||
.I config-file
|
||||
] [
|
||||
.B \-i
|
||||
.I pid-file
|
||||
] [
|
||||
.B \-p
|
||||
.I bgp-port-number
|
||||
] [
|
||||
.B \-P
|
||||
.I port-number
|
||||
] [
|
||||
.B \-A
|
||||
.I vty-address
|
||||
] [
|
||||
.B \-u
|
||||
.I user
|
||||
] [
|
||||
.B \-g
|
||||
.I group
|
||||
] [
|
||||
.B \-M
|
||||
.I module:options
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B bgpd
|
||||
is a routing component that works with the
|
||||
.B @PACKAGE_FULLNAME@
|
||||
routing engine.
|
||||
.SH OPTIONS
|
||||
Options available for the
|
||||
.B bgpd
|
||||
command:
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-daemon\fR
|
||||
Runs in daemon mode, forking and exiting from tty.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
|
||||
Specifies the config file to use for startup. If not specified this
|
||||
option will default to \fB\fI@CFG_SYSCONF@/bgpd.conf\fR.
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR
|
||||
Specify the group to run as. Default is \fI@enable_group@\fR.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
A brief message.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
|
||||
When bgpd starts its process identifier is written to
|
||||
\fB\fIpid-file\fR. The init system uses the recorded PID to stop or
|
||||
restart bgpd. The default is \fB\fI@CFG_STATE@/bgpd.pid\fR.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-bgp_port \fR\fIbgp-port-number\fR
|
||||
Set the port that bgpd will listen to for bgp data.
|
||||
.TP
|
||||
\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR
|
||||
Specify the port that the bgpd VTY will listen on. This defaults to
|
||||
2605, as specified in \fI/etc/services\fR.
|
||||
.TP
|
||||
\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR
|
||||
Specify the address that the bgpd VTY will listen on. Default is all
|
||||
interfaces.
|
||||
.TP
|
||||
\fB\-u\fR, \fB\-\-user \fR\fIuser\fR
|
||||
Specify the user to run as. Default is \fI@enable_user@\fR.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-retain\fR
|
||||
When the program terminates, retain routes added by \fBbgpd\fR.
|
||||
.TP
|
||||
\fB\-S\fR, \fB\-\-skip_runas\fR
|
||||
Skip setting the process effective user and group.
|
||||
.TP
|
||||
\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR
|
||||
Load a module at startup. May be specified more than once.
|
||||
The \fBsnmp\fR module may be available for
|
||||
\fBbgpd\fR, if the package was built with SNMP support.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Print the version and exit.
|
||||
.SH FILES
|
||||
.TP
|
||||
.BI @CFG_SBIN@/bgpd
|
||||
The default location of the
|
||||
.B bgpd
|
||||
binary.
|
||||
.TP
|
||||
.BI @CFG_SYSCONF@/bgpd.conf
|
||||
The default location of the
|
||||
.B bgpd
|
||||
config file.
|
||||
.TP
|
||||
.BI $(PWD)/bgpd.log
|
||||
If the
|
||||
.B bgpd
|
||||
process is config'd to output logs to a file, then you will find this
|
||||
file in the directory where you started \fBbgpd\fR.
|
||||
.SH WARNING
|
||||
This man page is intended to be a quick reference for command line
|
||||
options. The definitive document is the Info file \fB@PACKAGE_NAME@\fR.
|
||||
.SH DIAGNOSTICS
|
||||
The bgpd process may log to standard output, to a VTY, to a log
|
||||
file, or through syslog to the system logs. \fBbgpd\fR supports many
|
||||
debugging options, see the Info file, or the source for details.
|
||||
.SH "SEE ALSO"
|
||||
.BR ripd (8),
|
||||
.BR ripngd (8),
|
||||
.BR ospfd (8),
|
||||
.BR ospf6d (8),
|
||||
.BR isisd (8),
|
||||
.BR nhrpd (8),
|
||||
.BR zebra (8),
|
||||
.BR vtysh (1)
|
||||
.SH BUGS
|
||||
.B bgpd
|
||||
eats bugs for breakfast. If you have food for the maintainers try
|
||||
.BI @PACKAGE_BUGREPORT@
|
||||
.SH AUTHORS
|
||||
See
|
||||
.BI http://www.zebra.org
|
||||
and
|
||||
.BI @PACKAGE_URL@
|
||||
or the Info file for an accurate list of authors.
|
||||
|
2142
doc/bgpd.texi
557
doc/cli.md
@ -1,557 +0,0 @@
|
||||
FRR Command Line Interface
|
||||
==========================
|
||||
|
||||
Definition Grammar
|
||||
------------------
|
||||
|
||||
This is a reference for the syntax used when defining new CLI commands. An
|
||||
example definition is:
|
||||
|
||||
```
|
||||
DEFUN (command_name,
|
||||
command_name_cmd,
|
||||
--> "example <command|line [interface]> DEFINITION...",
|
||||
<..doc strings..>)
|
||||
```
|
||||
|
||||
The arrowed part is the definition string.
|
||||
|
||||
Explicit syntax rules in Flex and Bison may be found in lib/command_lex.l and
|
||||
lib/command_parse.y, respectively. If you can read BNF and regex those will be
|
||||
more useful than this document.
|
||||
|
||||
If the parser is throwing syntax or other errors and you can't figure out why,
|
||||
it's unlikely to be a bug in the parser. If the error message is not useful,
|
||||
please file a bug for a better error message. If all else fails, read the token
|
||||
definitions in the lexer source and the Bison BNF in the parser source.
|
||||
|
||||
Characters allowed in each token type:
|
||||
|
||||
Tokens
|
||||
------
|
||||
* `WORD` -- A token that begins with +, -, or a lowercase letter. It is
|
||||
an unchanging part of the command and will only match itself.
|
||||
Example: "show ip bgp", every token is a WORD.
|
||||
* `IPV4` -- 'A.B.C.D', matches an IPv4 address.
|
||||
* `IPV6` -- 'X:X::X:X', matches an IPv6 address.
|
||||
* `IPV4_PREFIX` -- 'A.B.C.D/M', matches an IPv4 prefix in CIDR notation.
|
||||
* `IPV6_PREFIX` -- 'X:X::X:X/M', matches an IPv6 prefix in CIDR notation.
|
||||
* `MAC` -- 'M:A:C', matches a 48-bit mac address
|
||||
* `MAC_PREFIX` -- 'M:A:C/M', matches a 48-bit mac address with a mask
|
||||
* `VARIABLE` -- Begins with a capital letter. Matches any input.
|
||||
* `RANGE` -- Numeric range delimited by parentheses, e.g. (-100 - 100) or
|
||||
(10-20). Will only match numbers in the range.
|
||||
|
||||
Rules
|
||||
-----
|
||||
* `<angle|brackets>` -- Contain sequences of tokens separated by pipes and
|
||||
provide mutual exclusion. Sequences may contain
|
||||
`<mutual|exclusion>` but not as the first token.
|
||||
Disallowed: `"example <<a|b> c|d>"`
|
||||
Allowed: `"example <a c|b c|d>"`
|
||||
* `[square brackets]` -- Contains sequences of tokens that are optional (can be
|
||||
omitted). `[<a|b>]` can be shortened to `[a|b]`.
|
||||
* `{curly|braces}` -- similar to angle brackets, but instead of mutual
|
||||
exclusion, curly braces indicate that one or more of the
|
||||
pipe-separated sequences may be provided in any order.
|
||||
* `VARIADICS...` -- Any token which accepts input (so anything except WORD)
|
||||
and that occurs as the last token of a line may be
|
||||
followed by an ellipsis, which indicates that input
|
||||
matching the token may be repeated an unlimited number
|
||||
of times.
|
||||
* `$name` -- Specify a variable name for the preceding token. See
|
||||
"Variable Names" below.
|
||||
|
||||
Some general notes:
|
||||
|
||||
* Options are allowed at the beginning of the command. The developer is
|
||||
entreated to use these extremely sparingly. They are most useful for
|
||||
implementing the 'no' form of configuration commands. Please think carefully
|
||||
before using them for anything else. There is usually a better solution, even
|
||||
if it is just separating out the command definition into separate ones.
|
||||
|
||||
* The developer should judiciously apply separation of concerns when defining
|
||||
CLI. CLI definitions for two unrelated or vaguely related commands or
|
||||
configuration items should be defined in separate commands. Clarity is
|
||||
preferred over LOC (within reason).
|
||||
|
||||
* The maximum number of space-separated tokens that can be entered is presently
|
||||
limited to 256. Please keep this limit in mind when implementing new CLI.
|
||||
|
||||
Variable Names
|
||||
--------------
|
||||
The parser tries to fill the "varname" field on each token. This can happen
|
||||
either manually or automatically. Manual specifications work by appending
|
||||
`"$name"` after the input specifier:
|
||||
|
||||
```
|
||||
foo bar$cmd WORD$name A.B.C.D$ip
|
||||
```
|
||||
|
||||
Note that you can also assign variable names to fixed input tokens, this can
|
||||
be useful if multiple commands share code. You can also use "$name" after a
|
||||
multiple-choice option:
|
||||
|
||||
```
|
||||
foo bar <A.B.C.D|X:X::X:X>$addr [optionA|optionB]$mode
|
||||
```
|
||||
|
||||
The variable name is in this case assigned to the last token in each of the
|
||||
branches.
|
||||
|
||||
Automatic assignment of variable names works by applying the following rules:
|
||||
|
||||
- manual names always have priority
|
||||
- a "[no]" at the beginning receives "no" as varname on the "no" token
|
||||
- VARIABLE tokens whose text is not "WORD" or "NAME" receive a cleaned lowercase
|
||||
version of the token text as varname, e.g. "ROUTE-MAP" becomes "route_map".
|
||||
- other variable tokens (i.e. everything except "fixed") receive the text of
|
||||
the preceding fixed token as varname, if one can be found. E.g.:
|
||||
"ip route A.B.C.D/M INTERFACE" assigns "route" to the "A.B.C.D/M" token.
|
||||
|
||||
These rules should make it possible to avoid manual varname assignment in 90%
|
||||
of the cases.
|
||||
|
||||
DEFPY
|
||||
-----
|
||||
|
||||
`DEFPY(...)` is an enhanced version of `DEFUN()` which is preprocessed by
|
||||
` python/clidef.py`. The python script parses the command definition string,
|
||||
extracts variable names and types, and generates a C wrapper function that
|
||||
parses the variables and passes them on. This means that in the CLI function
|
||||
body, you will receive additional parameters with appropriate types.
|
||||
|
||||
This is best explained by an example:
|
||||
|
||||
```
|
||||
DEFPY(func, func_cmd, "[no] foo bar A.B.C.D (0-99)$num", "...help...")
|
||||
|
||||
=>
|
||||
|
||||
func(self, vty, argc, argv, /* standard CLI arguments */
|
||||
|
||||
const char *no, /* unparsed "no" */
|
||||
struct in_addr bar, /* parsed IP address */
|
||||
const char *bar_str, /* unparsed IP address */
|
||||
long num, /* parsed num */
|
||||
const char *num_str) /* unparsed num */
|
||||
```
|
||||
|
||||
Note that as documented in the previous section, "bar" is automatically
|
||||
applied as variable name for "A.B.C.D". The python code then detects this
|
||||
is an IP address argument and generates code to parse it into a
|
||||
`struct in_addr`, passing it in `bar`. The raw value is passed in `bar_str`.
|
||||
The range/number argument works in the same way with the explicitly given
|
||||
variable name.
|
||||
|
||||
### Type rules
|
||||
|
||||
| Token(s) | Type | Value if omitted by user |
|
||||
|--------------------------|-------------|--------------------------|
|
||||
| `A.B.C.D` | `struct in_addr` | 0.0.0.0 |
|
||||
| `X:X::X:X` | `struct in6_addr` | :: |
|
||||
| `A.B.C.D + X:X::X:X` | `const union sockunion *` | NULL |
|
||||
| `A.B.C.D/M` | `const struct prefix_ipv4 *` | NULL |
|
||||
| `X:X::X:X/M` | `const struct prefix_ipv6 *` | NULL |
|
||||
| `A.B.C.D/M + X:X::X:X/M` | `const struct prefix *` | NULL |
|
||||
| `(0-9)` | `long` | 0 |
|
||||
| `VARIABLE` | `const char *` | NULL |
|
||||
| `word` | `const char *` | NULL |
|
||||
| _all other_ | `const char *` | NULL |
|
||||
|
||||
Note the following details:
|
||||
|
||||
* not all parameters are pointers, some are passed as values.
|
||||
* when the type is not `const char *`, there will be an extra `_str` argument
|
||||
with type `const char *`.
|
||||
* you can give a variable name not only to `VARIABLE` tokens but also to
|
||||
`word` tokens (e.g. constant words). This is useful if some parts of a
|
||||
command are optional. The type will be `const char *`.
|
||||
* `[no]` will be passed as `const char *no`.
|
||||
* pointers will be NULL when the argument is optional and the user did not
|
||||
use it.
|
||||
* if a parameter is not a pointer, but is optional and the user didn't use it,
|
||||
the default value will be passed. Check the `_str` argument if you need to
|
||||
determine whether the parameter was omitted.
|
||||
* if the definition contains multiple parameters with the same variable name,
|
||||
they will be collapsed into a single function parameter. The python code
|
||||
will detect if the types are compatible (i.e. IPv4 + IPv6 variantes) and
|
||||
choose a corresponding C type.
|
||||
* the standard DEFUN parameters (self, vty, argc, argv) are still present and
|
||||
can be used. A DEFUN can simply be **edited into a DEFPY without further
|
||||
changes and it will still work**; this allows easy forward migration.
|
||||
* a file may contain both DEFUN and DEFPY statements.
|
||||
|
||||
### Getting a parameter dump
|
||||
|
||||
The clidef.py script can be called to get a list of DEFUNs/DEFPYs with
|
||||
the parameter name/type list:
|
||||
|
||||
```
|
||||
lib/clippy python/clidef.py --all-defun --show lib/plist.c > /dev/null
|
||||
```
|
||||
|
||||
The generated code is printed to stdout, the info dump to stderr. The
|
||||
`--all-defun` argument will make it process DEFUN blocks as well as DEFPYs,
|
||||
which is useful prior to converting some DEFUNs. **The dump does not list
|
||||
the `_str` arguments** to keep the output shorter.
|
||||
|
||||
Note that the clidef.py script cannot be run with python directly, it needs
|
||||
to be run with _clippy_ since the latter makes the CLI parser available.
|
||||
|
||||
### Include & Makefile requirements
|
||||
|
||||
A source file that uses DEFPY needs to include the `_clippy.c` file **before
|
||||
all DEFPY statements**:
|
||||
|
||||
```
|
||||
/* GPL header */
|
||||
#include ...
|
||||
|
||||
...
|
||||
|
||||
#include "daemon/filename_clippy.c"
|
||||
|
||||
DEFPY(...)
|
||||
DEFPY(...)
|
||||
|
||||
install_element(...)
|
||||
```
|
||||
|
||||
This dependency needs to be marked in Makefile.am: (there is no ordering
|
||||
requirement)
|
||||
|
||||
```
|
||||
include ../common.am
|
||||
|
||||
# ...
|
||||
|
||||
# if linked into a LTLIBRARY (.la/.so):
|
||||
filename.lo: filename_clippy.c
|
||||
|
||||
# if linked into an executable or static library (.a):
|
||||
filename.o: filename_clippy.c
|
||||
```
|
||||
|
||||
Doc Strings
|
||||
-----------
|
||||
Each token in a command definition should be documented with a brief doc
|
||||
string that informs a user of the meaning and/or purpose of the subsequent
|
||||
command tree. These strings are provided as the last parameter to DEFUN macros,
|
||||
concatenated together and separated by an escaped newline ('\n'). These are
|
||||
best explained by example.
|
||||
|
||||
```
|
||||
DEFUN (config_terminal,
|
||||
config_terminal_cmd,
|
||||
"configure terminal",
|
||||
"Configuration from vty interface\n"
|
||||
"Configuration terminal\n")
|
||||
```
|
||||
|
||||
The last parameter is split into two lines for readability. Two newline
|
||||
delimited doc strings are present, one for each token in the command. The
|
||||
second string documents the functionality of the 'terminal' command in the
|
||||
'configure' tree.
|
||||
|
||||
Note that the first string, for 'configure' does not contain documentation for
|
||||
'terminal'. This is because the CLI is best envisioned as a tree, with tokens
|
||||
defining branches. An imaginary 'start' token is the root of every command in a
|
||||
CLI node. Each subsequent written token descends into a subtree, so the
|
||||
documentation for that token ideally summarizes all the functionality contained
|
||||
in the subtree.
|
||||
|
||||
A consequence of this structure is that the developer must be careful to use
|
||||
the same doc strings when defining multiple commands that are part of the same
|
||||
tree. Commands which share prefixes must share the same doc strings for those
|
||||
prefixes. On startup the parser will generate warnings if it notices
|
||||
inconsistent doc strings. Behavior is undefined; the same token may show up
|
||||
twice in completions, with different doc strings, or it may show up once with a
|
||||
random doc string. Parser warnings should be heeded and fixed to avoid
|
||||
confusing users.
|
||||
|
||||
The number of doc strings provided must be equal to the amount of tokens
|
||||
present in the command definition, read left to right, ignoring any special
|
||||
constructs.
|
||||
|
||||
In the examples below, each arrowed token needs a doc string.
|
||||
|
||||
```
|
||||
"show ip bgp"
|
||||
^ ^ ^
|
||||
|
||||
"command <foo|bar> [example]"
|
||||
^ ^ ^ ^
|
||||
```
|
||||
|
||||
Data Structures
|
||||
---------------
|
||||
On startup, the CLI parser sequentially parses each command string definition
|
||||
and constructs a directed graph with each token forming a node. This graph is
|
||||
the basis of the entire CLI system. It is used to match user input in order to
|
||||
generate command completions and match commands to functions.
|
||||
|
||||
There is one graph per CLI node (not the same as a graph node in the CLI
|
||||
graph). The CLI node struct keeps a reference to its graph (see lib/command.h).
|
||||
|
||||
While most of the graph maintains the form of a tree, special constructs
|
||||
outlined in the Rules section introduce some quirks. <>, [] and {} form
|
||||
self-contained 'subgraphs'. Each subgraph is a tree except that all of the
|
||||
'leaves' actually share a child node. This helps with minimizing graph size and
|
||||
debugging.
|
||||
|
||||
As an example, the subgraph generated by <foo|bar> looks like this:
|
||||
|
||||
.
|
||||
.
|
||||
|
|
||||
+----+---+
|
||||
+--- -+ FORK +----+
|
||||
| +--------+ |
|
||||
+--v---+ +--v---+
|
||||
| foo | | bar |
|
||||
+--+---+ +--+---+
|
||||
| +------+ |
|
||||
+------> JOIN <-----+
|
||||
+---+--+
|
||||
|
|
||||
.
|
||||
.
|
||||
|
||||
FORK and JOIN nodes are plumbing nodes that don't correspond to user input.
|
||||
They're necessary in order to deduplicate these constructs where applicable.
|
||||
|
||||
Options follow the same form, except that there is an edge from the FORK node
|
||||
to the JOIN node.
|
||||
|
||||
Keywords follow the same form, except that there is an edge from JOIN to FORK.
|
||||
Because of this the CLI graph cannot be called acyclic. There is special logic
|
||||
in the input matching code that keeps a stack of paths already taken through
|
||||
the node in order to disallow following the same path more than once.
|
||||
|
||||
Variadics are a bit special; they have an edge back to themselves, which allows
|
||||
repeating the same input indefinitely.
|
||||
|
||||
The leaves of the graph are nodes that have no out edges. These nodes are
|
||||
special; their data section does not contain a token, as most nodes do, or
|
||||
NULL, as in FORK/JOIN nodes, but instead has a pointer to a cmd_element. All
|
||||
paths through the graph that terminate on a leaf are guaranteed to be defined
|
||||
by that command. When a user enters a complete command, the command matcher
|
||||
tokenizes the input and executes a DFS on the CLI graph. If it is
|
||||
simultaneously able to exhaust all input (one input token per graph node), and
|
||||
then find exactly one leaf connected to the last node it reaches, then the
|
||||
input has matched the corresponding command and the command is executed. If it
|
||||
finds more than one node, then the command is ambiguous (more on this in
|
||||
deduplication). If it cannot exhaust all input, the command is unknown. If it
|
||||
exhausts all input but does not find an edge node, the command is incomplete.
|
||||
|
||||
The parser uses an incremental strategy to build the CLI graph for a node. Each
|
||||
command is parsed into its own graph, and then this graph is merged into the
|
||||
overall graph. During this merge step, the parser makes a best-effort attempt
|
||||
to remove duplicate nodes. If it finds a node in the overall graph that is
|
||||
equal to a node in the corresponding position in the command graph, it will
|
||||
intelligently merge the properties from the node in the command graph into the
|
||||
already-existing node. Subgraphs are also checked for isomorphism and merged
|
||||
where possible. The definition of whether two nodes are 'equal' is based on the
|
||||
equality of some set of token properties; read the parser source for the most
|
||||
up-to-date definition of equality.
|
||||
|
||||
When the parser is unable to deduplicate some complicated constructs, this
|
||||
can result in two identical paths through separate parts of the graph. If
|
||||
this occurs and the user enters input that matches these paths, they will
|
||||
receive an 'ambiguous command' error and will be unable to execute the command.
|
||||
Most of the time the parser can detect and warn about duplicate commands, but
|
||||
it will not always be able to do this. Hence care should be taken before
|
||||
defining a new command to ensure it is not defined elsewhere.
|
||||
|
||||
|
||||
Command handlers
|
||||
----------------
|
||||
The block that follows a CLI definition is executed when a user enters input
|
||||
that matches the definition. Its function signature looks like this:
|
||||
|
||||
int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
|
||||
|
||||
The first argument is the command definition struct. The last argument is an
|
||||
ordered array of tokens that correspond to the path taken through the graph,
|
||||
and the argument just prior to that is the length of the array.
|
||||
|
||||
The arrangement of the token array has changed from the prior incarnation of
|
||||
the CLI system. In the old system, missing arguments were padded with NULLs so
|
||||
that the same parts of a command would show up at the same indices regardless
|
||||
of what was entered. The new system does not perform such padding and therefore
|
||||
it is generally _incorrect_ to assume consistent indices in this array. As a
|
||||
simple example:
|
||||
|
||||
Command definition:
|
||||
```
|
||||
command [foo] <bar|baz>
|
||||
```
|
||||
|
||||
User enters:
|
||||
```
|
||||
command foo bar
|
||||
```
|
||||
|
||||
Array:
|
||||
```
|
||||
[0] -> command
|
||||
[1] -> foo
|
||||
[2] -> bar
|
||||
```
|
||||
|
||||
User enters:
|
||||
```
|
||||
command baz
|
||||
```
|
||||
|
||||
Array:
|
||||
```
|
||||
[0] -> command
|
||||
[1] -> baz
|
||||
```
|
||||
|
||||
|
||||
|
||||
Command abbreviation & matching priority
|
||||
----------------------------------------
|
||||
As in the prior implementation, it is possible for users to elide parts of
|
||||
tokens when the CLI matcher does not need them to make an unambiguous match.
|
||||
This is best explained by example.
|
||||
|
||||
Command definitions:
|
||||
```
|
||||
command dog cow
|
||||
command dog crow
|
||||
```
|
||||
|
||||
User input:
|
||||
```
|
||||
c d c -> ambiguous command
|
||||
c d co -> match "command dog cow"
|
||||
```
|
||||
|
||||
In the new implementation, this functionality has improved. Where previously
|
||||
the parser would stop at the first ambiguous token, it will now look ahead and
|
||||
attempt to disambiguate based on tokens later on in the input string.
|
||||
|
||||
Command definitions:
|
||||
```
|
||||
show ip bgp A.B.C.D
|
||||
show ipv6 bgp X:X::X:X
|
||||
```
|
||||
|
||||
User enters:
|
||||
```
|
||||
s i b 4.3.2.1 -> match "show ip bgp A.B.C.D"
|
||||
s i b ::e0 -> match "show ipv6 bgp X:X::X:X"
|
||||
```
|
||||
|
||||
Previously both of these commands would be ambiguous since 'i' does not
|
||||
explicitly select either 'ip' or 'ipv6'. However, since the user later provides
|
||||
a token that matches only one of the commands (an IPv4 or IPv6 address) the
|
||||
parser is able to look ahead and select the appropriate command. This has some
|
||||
implications for parsing the argv*[] that is passed to the command handler.
|
||||
|
||||
Now consider a command definition such as:
|
||||
```
|
||||
command <foo|VAR>
|
||||
```
|
||||
|
||||
'foo' only matches the string 'foo', but 'VAR' matches any input, including
|
||||
'foo'. Who wins? In situations like this the matcher will always choose the
|
||||
'better' match, so 'foo' will win.
|
||||
|
||||
Consider also:
|
||||
```
|
||||
show <ip|ipv6> foo
|
||||
```
|
||||
|
||||
User input:
|
||||
```
|
||||
show ip foo
|
||||
```
|
||||
|
||||
'ip' partially matches 'ipv6' but exactly matches 'ip', so 'ip' will win.
|
||||
|
||||
|
||||
struct cmd_token
|
||||
----------------
|
||||
|
||||
```
|
||||
/* Command token struct. */
|
||||
struct cmd_token
|
||||
{
|
||||
enum cmd_token_type type; // token type
|
||||
u_char attr; // token attributes
|
||||
bool allowrepeat; // matcher allowed to match token repetitively?
|
||||
|
||||
char *text; // token text
|
||||
char *desc; // token description
|
||||
long long min, max; // for ranges
|
||||
char *arg; // user input that matches this token
|
||||
char *varname; // variable name
|
||||
};
|
||||
```
|
||||
|
||||
This struct is used in the CLI graph to match input against. It is also used to
|
||||
pass user input to command handler functions, as it is frequently useful for
|
||||
handlers to have access to that information. When a command is matched, the
|
||||
sequence of cmd_tokens that form the matching path are duplicated and placed in
|
||||
order into argv*[]. Before this happens the ->arg field is set to point at the
|
||||
snippet of user input that matched it.
|
||||
|
||||
For most nontrivial commands the handler function will need to determine which
|
||||
of the possible matching inputs was entered. Previously this was done by
|
||||
looking at the first few characters of input. This is now considered an
|
||||
anti-pattern and should be avoided. Instead, the ->type or ->text fields for
|
||||
this logic. The ->type field can be used when the possible inputs differ in
|
||||
type. When the possible types are the same, use the ->text field. This field
|
||||
has the full text of the corresponding token in the definition string and using
|
||||
it makes for much more readable code. An example is helpful.
|
||||
|
||||
Command definition:
|
||||
```
|
||||
command <(1-10)|foo|BAR>
|
||||
```
|
||||
|
||||
In this example, the user may enter any one of:
|
||||
* an integer between 1 and 10
|
||||
* "foo"
|
||||
* anything at all
|
||||
|
||||
If the user enters "command f", then:
|
||||
|
||||
```
|
||||
argv[1]->type == WORD_TKN
|
||||
argv[1]->arg == "f"
|
||||
argv[1]->text == "foo"
|
||||
```
|
||||
|
||||
Range tokens have some special treatment; a token with ->type == RANGE_TKN will
|
||||
have the ->min and ->max fields set to the bounding values of the range.
|
||||
|
||||
|
||||
Permutations
|
||||
------------
|
||||
Finally, it is sometimes useful to check all the possible combinations of input
|
||||
that would match an arbitrary definition string. There is a tool in tools/
|
||||
called 'permutations' that reads CLI definition strings on stdin and prints out
|
||||
all matching input permutations. It also dumps a text representation of the
|
||||
graph, which is more useful for debugging than anything else. It looks like
|
||||
this:
|
||||
|
||||
```
|
||||
$ ./permutations "show [ip] bgp [<view|vrf> WORD]"
|
||||
|
||||
show ip bgp view WORD
|
||||
show ip bgp vrf WORD
|
||||
show ip bgp
|
||||
show bgp view WORD
|
||||
show bgp vrf WORD
|
||||
show bgp
|
||||
```
|
||||
|
||||
This functionality is also built into VTY/VTYSH; the 'list permutations'
|
||||
command will list all possible matching input permutations in the current CLI
|
||||
node.
|
@ -1,21 +0,0 @@
|
||||
@c -*- texinfo -*-
|
||||
@c @configure_input@
|
||||
|
||||
@c Set variables
|
||||
@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}
|
||||
|
||||
@c These may vary with installation environment.
|
||||
@set INSTALL_PREFIX_ETC @CFG_SYSCONF@
|
||||
@set INSTALL_PREFIX_SBIN @CFG_SBIN@
|
||||
@set INSTALL_PREFIX_STATE @CFG_STATE@
|
||||
@set INSTALL_PREFIX_MODULES @CFG_MODULE@
|
||||
@set INSTALL_USER @enable_user@
|
||||
@set INSTALL_GROUP @enable_group@
|
||||
@set INSTALL_VTY_GROUP @enable_vty_group@
|
@ -1,31 +1,47 @@
|
||||
Building FRR on CentOS 6 from Git Source
|
||||
CentOS 6
|
||||
========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm_build.md on how to build a rpm package)
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
|
||||
Instructions are tested with `CentOS 6.8` on `x86_64` platform
|
||||
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
|
||||
|
||||
Warning:
|
||||
--------
|
||||
``CentOS 6`` is very old and not fully supported by the FRR community
|
||||
anymore. Building FRR takes multiple manual steps to update the build
|
||||
system with newer packages than what's available from the archives.
|
||||
However, the built packages can still be installed afterwards on
|
||||
a standard ``CentOS 6`` without any special packages.
|
||||
|
||||
Support for CentOS 6 is now on a best-effort base by the community.
|
||||
|
||||
CentOS 6 restrictions:
|
||||
----------------------
|
||||
|
||||
- PIMd is not supported on `CentOS 6`. Upgrade to `CentOS 7` if PIMd is
|
||||
needed
|
||||
- MPLS is not supported on `CentOS 6`. MPLS requires Linux Kernel 4.5 or
|
||||
higher (LDP can be built, but may have limited use without MPLS)
|
||||
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
||||
with (IFLA_INFO_SLAVE_KIND does not exist in the kernel headers, you
|
||||
can use a newer kernel + headers to get this functionality)
|
||||
- frr_reload.py will not work, as this requires Python 2.7, and CentOS 6
|
||||
only has 2.6. You can install Python 2.7 via IUS, but it won't work
|
||||
properly unless you compile and install the ipaddr package for it.
|
||||
- PIMd is not supported on ``CentOS 6``. Upgrade to ``CentOS 7`` if
|
||||
PIMd is needed
|
||||
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
|
||||
or higher (LDP can be built, but may have limited use without MPLS)
|
||||
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
||||
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
|
||||
you can use a newer kernel + headers to get this functionality)
|
||||
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
|
||||
6 only has 2.6. You can install Python 2.7 via IUS, but it won't work
|
||||
properly unless you compile and install the ipaddr package for it.
|
||||
- Building the package requires Sphinx >= 1.1. Only a non-standard
|
||||
package provides a newer sphinx and requires manual installation
|
||||
(see below)
|
||||
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo yum install git autoconf automake libtool make gawk \
|
||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||
json-c-devel pam-devel flex epel-release perl-XML-LibXML \
|
||||
@ -34,13 +50,18 @@ Add packages:
|
||||
Install newer version of bison (CentOS 6 package source is too old) from
|
||||
CentOS 7
|
||||
|
||||
::
|
||||
|
||||
sudo yum install rpm-build
|
||||
curl -O http://vault.centos.org/7.0.1406/os/Source/SPackages/bison-2.7-4.el7.src.rpm
|
||||
rpmbuild --rebuild ./bison-2.7-4.el7.src.rpm
|
||||
sudo yum install ./rpmbuild/RPMS/x86_64/bison-2.7-4.el6.x86_64.rpm
|
||||
rm -rf rpmbuild
|
||||
|
||||
Install newer version of autoconf and automake (Package versions are too old)
|
||||
Install newer version of autoconf and automake (Package versions are too
|
||||
old)
|
||||
|
||||
::
|
||||
|
||||
curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
|
||||
tar xvf autoconf-2.69.tar.gz
|
||||
@ -58,35 +79,69 @@ Install newer version of autoconf and automake (Package versions are too old)
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
Install `Python 2.7` in parallel to default 2.6.
|
||||
Make sure you've install EPEL (`epel-release` as above). Then install current
|
||||
`python27`, `python27-devel` and `pytest`
|
||||
Install ``Python 2.7`` in parallel to default 2.6. Make sure you've
|
||||
install EPEL (``epel-release`` as above). Then install current
|
||||
``python27``, ``python27-devel`` and ``pytest``
|
||||
|
||||
::
|
||||
|
||||
sudo rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
|
||||
sudo rpm -ivh https://centos6.iuscommunity.org/ius-release.rpm
|
||||
sudo yum install python27 python27-pip python27-devel
|
||||
sudo pip2.7 install pytest
|
||||
|
||||
Please note that `CentOS 6` needs to keep python pointing to version 2.6
|
||||
for `yum` to keep working, so don't create a symlink for python2.7 to python
|
||||
Please note that ``CentOS 6`` needs to keep python pointing to version
|
||||
2.6 for ``yum`` to keep working, so don't create a symlink for python2.7
|
||||
to python
|
||||
|
||||
Install newer ``Sphinx-Build`` based on ``Python 2.7``
|
||||
|
||||
Create a new repo ``/etc/yum.repos.d/puias6.repo`` with the following contents:
|
||||
|
||||
::
|
||||
|
||||
### Name: RPM Repository for RHEL 6 - PUIAS (used for Sphinx-Build)
|
||||
### URL: http://springdale.math.ias.edu/data/puias/computational
|
||||
[puias-computational]
|
||||
name = RPM Repository for RHEL 6 - Sphinx-Build
|
||||
baseurl = http://springdale.math.ias.edu/data/puias/computational/$releasever/$basearch
|
||||
#mirrorlist =
|
||||
enabled = 1
|
||||
protect = 0
|
||||
gpgkey =
|
||||
gpgcheck = 0
|
||||
|
||||
Update rpm database & Install newer sphinx
|
||||
|
||||
::
|
||||
|
||||
sudo yum update
|
||||
sudo yum install python27-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvt
|
||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -116,11 +171,15 @@ an example.)
|
||||
--enable-babeld \
|
||||
--with-pkg-git-version \
|
||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||
make
|
||||
make check PYTHON=/usr/bin/python2.7
|
||||
sudo make install
|
||||
make SPHINXBUILD=sphinx-build2.7
|
||||
make check PYTHON=/usr/bin/python2.7 SPHINXBUILD=sphinx-build2.7
|
||||
sudo make SPHINXBUILD=sphinx-build2.7 install
|
||||
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
### Create empty FRR configuration files
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /etc/frr
|
||||
sudo touch /etc/frr/zebra.conf
|
||||
@ -138,20 +197,28 @@ an example.)
|
||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||
sudo chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Install daemon config file
|
||||
Install daemon config file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/daemons /etc/frr/
|
||||
sudo chown frr:frr /etc/frr/daemons
|
||||
|
||||
### Edit /etc/frr/daemons as needed to select the required daemons
|
||||
Edit /etc/frr/daemons as needed to select the required daemons
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Look for the section with `watchfrr_enable=...` and `zebra=...` etc.
|
||||
Enable the daemons as required by changing the value to `yes`
|
||||
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||
Enable the daemons as required by changing the value to ``yes``
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and set the following values (ignore the other
|
||||
Edit ``/etc/sysctl.conf`` and set the following values (ignore the other
|
||||
settings)
|
||||
|
||||
::
|
||||
|
||||
# Controls IP packet forwarding
|
||||
net.ipv4.ip_forward = 1
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
@ -161,14 +228,28 @@ settings)
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
||||
|
||||
### Add init.d startup files
|
||||
Add init.d startup files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 755 redhat/frr.init /etc/init.d/frr
|
||||
sudo chkconfig --add frr
|
||||
|
||||
### Enable frr daemon at startup
|
||||
Enable frr daemon at startup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo chkconfig frr on
|
||||
|
||||
### Start FRR manually (or reboot)
|
||||
Start FRR manually (or reboot)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo /etc/init.d/frr start
|
@ -1,44 +1,53 @@
|
||||
Building FRR on CentOS 7 from Git Source
|
||||
CentOS 7
|
||||
========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm_build.md on how to build a rpm package)
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
|
||||
CentOS 7 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `CentOS 7` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
- MPLS is not supported on ``CentOS 7`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS)
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo yum install git autoconf automake libtool make gawk \
|
||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||
json-c-devel pam-devel bison flex pytest c-ares-devel \
|
||||
perl-XML-LibXML python-devel systemd-devel
|
||||
perl-XML-LibXML python-devel systemd-devel python-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvt
|
||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -73,7 +82,11 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /etc/frr
|
||||
sudo touch /etc/frr/zebra.conf
|
||||
@ -92,20 +105,28 @@ an example.)
|
||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||
sudo chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Install daemon config file
|
||||
Install daemon config file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/daemons /etc/frr/
|
||||
sudo chown frr:frr /etc/frr/daemons
|
||||
|
||||
### Edit /etc/frr/daemons as needed to select the required daemons
|
||||
Edit /etc/frr/daemons as needed to select the required daemons
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Look for the section with `watchfrr_enable=...` and `zebra=...` etc.
|
||||
Enable the daemons as required by changing the value to `yes`
|
||||
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||
Enable the daemons as required by changing the value to ``yes``
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Create a new file `/etc/sysctl.d/90-routing-sysctl.conf` with the
|
||||
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
|
||||
following content:
|
||||
|
||||
::
|
||||
|
||||
# Sysctl for routing
|
||||
#
|
||||
# Routing: We need to forward packets
|
||||
@ -114,17 +135,35 @@ following content:
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
||||
|
||||
### Install frr Service and redhat init files
|
||||
Install frr Service and redhat init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
|
||||
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
|
||||
|
||||
### Register the systemd files
|
||||
Register the systemd files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl preset frr.service
|
||||
|
||||
### Enable required frr at startup
|
||||
Enable required frr at startup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl enable frr
|
||||
|
||||
### Reboot or start FRR manually
|
||||
Reboot or start FRR manually
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl start frr
|
@ -1,33 +1,40 @@
|
||||
Building FRR on Debian 8 from Git Source
|
||||
Debian 8
|
||||
========================================
|
||||
|
||||
Debian 8 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `Debian 8` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
- MPLS is not supported on ``Debian 8`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS)
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install git autoconf automake libtool make gawk \
|
||||
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
|
||||
python-pip libc-ares-dev python3-dev
|
||||
python-pip libc-ares-dev python3-dev python3-sphinx
|
||||
|
||||
Install newer pytest (>3.0) from pip
|
||||
|
||||
::
|
||||
|
||||
sudo pip install pytest
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo addgroup --system --gid 92 frr
|
||||
sudo addgroup --system --gid 85 frrvty
|
||||
@ -35,10 +42,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /bin/false frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -68,7 +79,10 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
@ -84,11 +98,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -97,35 +114,43 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
### Troubleshooting
|
||||
Troubleshooting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
**Local state directory**
|
||||
|
||||
The local state directory must exist and have the correct permissions applied
|
||||
for the frrouting daemons to start. In the above ./configure example the
|
||||
local state directory is set to /var/run/frr (--localstatedir=/var/run/frr)
|
||||
Debian considers /var/run/frr to be temporary and this is removed after a
|
||||
reboot.
|
||||
The local state directory must exist and have the correct permissions
|
||||
applied for the frrouting daemons to start. In the above ./configure
|
||||
example the local state directory is set to /var/run/frr
|
||||
(--localstatedir=/var/run/frr) Debian considers /var/run/frr to be
|
||||
temporary and this is removed after a reboot.
|
||||
|
||||
When using a different local state directory you need to create the new
|
||||
directory and change the ownership to the frr user, for example:
|
||||
|
||||
::
|
||||
|
||||
mkdir /var/opt/frr
|
||||
chown frr /var/opt/frr
|
||||
|
||||
**Shared library error**
|
||||
|
||||
If you try and start any of the frrouting daemons you may see the below error
|
||||
due to the frrouting shared library directory not being found:
|
||||
If you try and start any of the frrouting daemons you may see the below
|
||||
error due to the frrouting shared library directory not being found:
|
||||
|
||||
::
|
||||
|
||||
./zebra: error while loading shared libraries: libfrr.so.0: cannot open shared object file: No such file or directory
|
||||
|
||||
The fix is to add the following line to /etc/ld.so.conf which will continue to
|
||||
reference the library directory after the system reboots. To load the library
|
||||
directory path immediately run the ldconfig command after adding the line to
|
||||
the file eg:
|
||||
The fix is to add the following line to /etc/ld.so.conf which will
|
||||
continue to reference the library directory after the system reboots. To
|
||||
load the library directory path immediately run the ldconfig command
|
||||
after adding the line to the file eg:
|
||||
|
||||
::
|
||||
|
||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||
ldconfig
|
@ -1,4 +1,4 @@
|
||||
Building FRR on Debian 9 from Git Source
|
||||
Debian 9
|
||||
========================================
|
||||
|
||||
Install required packages
|
||||
@ -6,17 +6,22 @@ Install required packages
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install git autoconf automake libtool make \
|
||||
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
|
||||
python-pip libc-ares-dev python3-dev python-pytest
|
||||
python-pip libc-ares-dev python3-dev python-pytest python3-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo addgroup --system --gid 92 frr
|
||||
sudo addgroup --system --gid 85 frrvty
|
||||
@ -24,10 +29,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /bin/false frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
git checkout stable/3.0
|
||||
@ -58,7 +67,10 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 755 -o frr -g frr -d /var/opt/frr
|
||||
@ -75,11 +87,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -88,21 +103,29 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
### Troubleshooting
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
**Shared library error**
|
||||
Shared library error
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you try and start any of the frrouting daemons you may see the below error
|
||||
due to the frrouting shared library directory not being found:
|
||||
If you try and start any of the frrouting daemons you may see the below
|
||||
error due to the frrouting shared library directory not being found:
|
||||
|
||||
./zebra: error while loading shared libraries: libfrr.so.0: cannot open shared object file: No such file or directory
|
||||
::
|
||||
|
||||
The fix is to add the following line to /etc/ld.so.conf which will continue to
|
||||
reference the library directory after the system reboots. To load the library
|
||||
directory path immediately run the ldconfig command after adding the line to
|
||||
the file eg:
|
||||
./zebra: error while loading shared libraries: libfrr.so.0: cannot open
|
||||
shared object file: No such file or directory
|
||||
|
||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||
ldconfig
|
||||
The fix is to add the following line to /etc/ld.so.conf which will
|
||||
continue to reference the library directory after the system reboots. To
|
||||
load the library directory path immediately run the ldconfig command
|
||||
after adding the line to the file eg:
|
||||
|
||||
::
|
||||
|
||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||
ldconfig
|
@ -1,19 +1,21 @@
|
||||
Building FRR on Fedora 24 from Git Source
|
||||
Fedora 24
|
||||
=========================================
|
||||
|
||||
(As an alternative to this installation, you may prefer to create a FRR
|
||||
rpm package yourself and install that package instead. See instructions
|
||||
in redhat/README.rpm_build.md on how to build a rpm package)
|
||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo dnf install git autoconf automake libtool make gawk \
|
||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||
json-c-devel pam-devel perl-XML-LibXML pytest bison flex \
|
||||
c-ares-devel python3-devel
|
||||
c-ares-devel python3-devel python3-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
@ -21,17 +23,24 @@ Get FRR, compile it and install it (from Git)
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvt
|
||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -65,7 +74,11 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /etc/frr
|
||||
sudo touch /etc/frr/zebra.conf
|
||||
@ -85,21 +98,28 @@ an example.)
|
||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||
sudo chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Install daemon config file
|
||||
Install daemon config file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/daemons /etc/frr/
|
||||
sudo chown frr:frr /etc/frr/daemons
|
||||
|
||||
### Edit /etc/frr/daemons as needed to select the required daemons
|
||||
Edit /etc/frr/daemons as needed to select the required daemons
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Look for the section with `watchfrr_enable=...` and `zebra=...` etc.
|
||||
Enable the daemons as required by changing the value to `yes`
|
||||
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||
Enable the daemons as required by changing the value to ``yes``
|
||||
|
||||
### Enable IP & IPv6 forwarding (and MPLS)
|
||||
Enable IP & IPv6 forwarding (and MPLS)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Create a new file `/etc/sysctl.d/90-routing-sysctl.conf` with the
|
||||
following content:
|
||||
(Please make sure to list all interfaces with required MPLS similar
|
||||
to `net.mpls.conf.eth0.input=1`)
|
||||
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
|
||||
following content: (Please make sure to list all interfaces with
|
||||
required MPLS similar to ``net.mpls.conf.eth0.input=1``)
|
||||
|
||||
::
|
||||
|
||||
# Sysctl for routing
|
||||
#
|
||||
@ -115,9 +135,14 @@ to `net.mpls.conf.eth0.input=1`)
|
||||
|
||||
Load the modifed sysctl's on the system:
|
||||
|
||||
::
|
||||
|
||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
||||
|
||||
Create a new file `/etc/modules-load.d/mpls.conf` with the following content:
|
||||
Create a new file ``/etc/modules-load.d/mpls.conf`` with the following
|
||||
content:
|
||||
|
||||
::
|
||||
|
||||
# Load MPLS Kernel Modules
|
||||
mpls-router
|
||||
@ -125,14 +150,28 @@ Create a new file `/etc/modules-load.d/mpls.conf` with the following content:
|
||||
|
||||
And load the kernel modules on the running system:
|
||||
|
||||
::
|
||||
|
||||
sudo modprobe mpls-router mpls-iptunnel
|
||||
|
||||
### Install frr Service and redhat init files
|
||||
Install frr Service and redhat init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
|
||||
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
|
||||
|
||||
### Enable required frr at startup
|
||||
Enable required frr at startup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl enable frr
|
||||
|
||||
### Reboot or start FRR manually
|
||||
Reboot or start FRR manually
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo systemctl start frr
|
@ -1,27 +1,29 @@
|
||||
Building FRR on FreeBSD 10 from Git Source
|
||||
FreeBSD 10
|
||||
==========================================
|
||||
|
||||
FreeBSD 10 restrictions:
|
||||
------------------------
|
||||
|
||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
(Allow the install of the package managment tool if this is first package
|
||||
install and asked)
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
||||
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
|
||||
bison flex py27-pytest c-ares python3
|
||||
bison flex py27-pytest c-ares python3 py-sphinx
|
||||
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin):
|
||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
||||
takes preference in path)
|
||||
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||
as part of the base OS which takes preference in path)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/flex
|
||||
|
||||
@ -31,7 +33,10 @@ Get FRR, compile it and install it (from Git)
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
pw groupadd frr -g 101
|
||||
pw groupadd frrvty -g 102
|
||||
@ -41,6 +46,8 @@ using any packages**
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -68,7 +75,11 @@ an example)
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/local/etc/frr
|
||||
sudo touch /usr/local/etc/frr/zebra.conf
|
||||
sudo touch /usr/local/etc/frr/bgpd.conf
|
||||
@ -83,12 +94,16 @@ an example)
|
||||
sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||
sudo chmod 640 /usr/local/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
@ -1,27 +1,29 @@
|
||||
Building FRR on FreeBSD 11 from Git Source
|
||||
FreeBSD 11
|
||||
==========================================
|
||||
|
||||
FreeBSD 11 restrictions:
|
||||
------------------------
|
||||
|
||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
(Allow the install of the package managment tool if this is first package
|
||||
install and asked)
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
||||
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
|
||||
bison flex py27-pytest c-ares python3
|
||||
bison flex py27-pytest c-ares python3 py-sphinx
|
||||
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin):
|
||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
||||
takes preference in path)
|
||||
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||
as part of the base OS which takes preference in path)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/flex
|
||||
|
||||
@ -31,7 +33,10 @@ Get FRR, compile it and install it (from Git)
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
pw groupadd frr -g 101
|
||||
pw groupadd frrvty -g 102
|
||||
@ -41,6 +46,8 @@ using any packages**
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -68,7 +75,11 @@ an example)
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/local/etc/frr
|
||||
sudo touch /usr/local/etc/frr/zebra.conf
|
||||
sudo touch /usr/local/etc/frr/bgpd.conf
|
||||
@ -83,12 +94,16 @@ an example)
|
||||
sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||
sudo chmod 640 /usr/local/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
@ -1,32 +1,39 @@
|
||||
Building FRR on FreeBSD 9 from Git Source
|
||||
FreeBSD 9
|
||||
=========================================
|
||||
|
||||
FreeBSD 9 restrictions:
|
||||
-----------------------
|
||||
|
||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
(Allow the install of the package managment tool if this is first package
|
||||
install and asked)
|
||||
Add packages: (Allow the install of the package managment tool if this
|
||||
is first package install and asked)
|
||||
|
||||
::
|
||||
|
||||
pkg install -y git autoconf automake libtool gmake gawk \
|
||||
pkgconf texinfo json-c bison flex py27-pytest c-ares \
|
||||
python3
|
||||
python3 py-sphinx
|
||||
|
||||
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||
installed in /usr/local/bin):
|
||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
||||
takes preference in path)
|
||||
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||
as part of the base OS which takes preference in path)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/flex
|
||||
|
||||
For building with clang (instead of gcc), upgrade clang from 3.4 default to 3.6 *This is needed to build FreeBSD packages as well - for packages clang is default* (Clang 3.4 as shipped with FreeBSD 9 crashes during compile)
|
||||
For building with clang (instead of gcc), upgrade clang from 3.4 default
|
||||
to 3.6 *This is needed to build FreeBSD packages as well - for packages
|
||||
clang is default* (Clang 3.4 as shipped with FreeBSD 9 crashes during
|
||||
compile)
|
||||
|
||||
::
|
||||
|
||||
pkg install clang36
|
||||
pkg delete clang34
|
||||
@ -39,7 +46,10 @@ Get FRR, compile it and install it (from Git)
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
pw groupadd frr -g 101
|
||||
pw groupadd frrvty -g 102
|
||||
@ -49,6 +59,8 @@ using any packages**
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -76,7 +88,11 @@ an example)
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/local/etc/frr
|
||||
sudo touch /usr/local/etc/frr/zebra.conf
|
||||
sudo touch /usr/local/etc/frr/bgpd.conf
|
||||
@ -91,12 +107,16 @@ an example)
|
||||
sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||
sudo chmod 640 /usr/local/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
108
doc/developer/Building_FRR_on_LEDE-OpenWRT.rst
Normal file
@ -0,0 +1,108 @@
|
||||
OpenWRT/LEDE
|
||||
=============================================
|
||||
|
||||
- for the moment because of cross compile problems, master is not
|
||||
supported, only up to 3.0
|
||||
- LDP can't be built because of missing Perl-XML-LibXML in OpenWRT/LEDE
|
||||
tree
|
||||
|
||||
Prepare build environment
|
||||
-------------------------
|
||||
|
||||
https://lede-project.org/docs/guide-developer/install-buildsystem
|
||||
|
||||
for
|
||||
|
||||
Ubuntu 12.04LTS:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential subversion git-core \
|
||||
libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc \
|
||||
libxml-parser-perl mercurial bzr ecj cvs unzip python3-sphinx
|
||||
|
||||
Ubuntu 64bit:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential subversion libncurses5-dev zlib1g-dev \
|
||||
gawk gcc-multilib flex git-core gettext libssl-dev python3-sphinx
|
||||
|
||||
Debian 8 Jessie:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext unzip zlib1g-dev file python python3-sphinx
|
||||
|
||||
Debian 9 Stretch:
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install build-essential libncurses5-dev gawk git subversion \
|
||||
libssl-dev gettext zlib1g-dev python3-sphinx
|
||||
|
||||
Centos x86-64 (some packages require EPEL):
|
||||
|
||||
::
|
||||
|
||||
yum install subversion binutils bzip2 gcc gcc-c++ gawk gettext flex \
|
||||
ncurses-devel zlib-devel zlib-static make patch unzip glibc glibc-devel \
|
||||
perl-ExtUtils-MakeMaker glibc-static quilt ncurses-libs sed sdcc bison \
|
||||
intltool sharutils wget git-core openssl-devel xz python-sphinx
|
||||
|
||||
Fedora 24 - 64Bit:
|
||||
|
||||
::
|
||||
|
||||
dnf install -y subversion binutils bzip2 gcc gcc-c++ gawk gettext git-core \
|
||||
unzip ncurses-devel ncurses-compat-libs zlib-devel zlib-static make \
|
||||
flex patch perl-ExtUtils-MakeMaker perl-Thread-Queue glibc glibc-devel \
|
||||
glibc-static quilt sed sdcc intltool sharutils bison wget openssl-devel \
|
||||
python3-sphinx
|
||||
|
||||
Get LEDE Sources (from Git)
|
||||
---------------------------
|
||||
|
||||
LEDE and OpenWRT is planned to remerge and won't cover the similar
|
||||
OpenWRT build As normal user: git clone
|
||||
https://git.lede-project.org/source.git lede cd lede ./scripts/feeds
|
||||
update -a ./scripts/feeds install -a cd feeds/routing git pull origin
|
||||
pull/319/head ln -s ../../../feeds/routing/frr/
|
||||
../../package/feeds/routing/ cd ../.. make menuconfig
|
||||
|
||||
Select the needed target then select needed packages in Network ->
|
||||
Routing and Redirection -> frr, exit and save
|
||||
|
||||
::
|
||||
|
||||
make or make package/frr/compile
|
||||
|
||||
It may be possible that on first build ``make package/frr/compile`` not
|
||||
to work and it may be needed to run a ``make`` for the entire build
|
||||
envronment, add V=s for debugging
|
||||
|
||||
Work with sources
|
||||
-----------------
|
||||
|
||||
To update the rc1 version or add other options, the Makefile is found in
|
||||
feeds/routing/frr
|
||||
|
||||
edit: PKG\_VERSION:= PKG\_SOURCE\_VERSION:=
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
|
||||
DAEMONS= or don't install unneded packages For example: zebra bgpd ldpd
|
||||
isisd nhrpd ospfd ospf6d pimd ripd ripngd
|
||||
|
||||
Enable the serivce
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- service frr enable
|
||||
|
||||
Start the service
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
- service frr start
|
@ -1,50 +1,66 @@
|
||||
Building FRR on NetBSD 6 from Git Source
|
||||
NetBSD 6
|
||||
========================================
|
||||
|
||||
NetBSD 6 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``NetBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Configure Package location:
|
||||
|
||||
::
|
||||
|
||||
PKG_PATH="ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
|
||||
export PKG_PATH
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
sudo pkg_add git autoconf automake libtool gmake gawk openssl \
|
||||
pkg-config json-c python27 py27-test python35
|
||||
pkg-config json-c python27 py27-test python35 py-sphinx
|
||||
|
||||
Install SSL Root Certificates (for git https access):
|
||||
|
||||
::
|
||||
|
||||
sudo pkg_add mozilla-rootcerts
|
||||
sudo touch /etc/openssl/openssl.cnf
|
||||
sudo mozilla-rootcerts install
|
||||
|
||||
Select default Python and py.test
|
||||
|
||||
::
|
||||
|
||||
sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
|
||||
sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
------------------------------------------------
|
||||
---------------------------------------------
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -g 93 frrvty
|
||||
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
||||
-d /nonexistent -s /sbin/nologin frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -72,7 +88,11 @@ an example)
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /var/log/frr
|
||||
sudo mkdir /usr/pkg/etc/frr
|
||||
sudo touch /usr/pkg/etc/frr/zebra.conf
|
||||
@ -88,23 +108,35 @@ an example)
|
||||
sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
|
||||
sudo chmod 640 /usr/pkg/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
||||
|
||||
Install rc.d init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
### Install rc.d init files
|
||||
cp pkgsrc/*.sh /etc/rc.d/
|
||||
chmod 555 /etc/rc.d/*.sh
|
||||
|
||||
### Enable FRR processes
|
||||
Enable FRR processes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(Enable the required processes only)
|
||||
|
||||
::
|
||||
|
||||
echo "zebra=YES" >> /etc/rc.conf
|
||||
echo "bgpd=YES" >> /etc/rc.conf
|
||||
echo "ospfd=YES" >> /etc/rc.conf
|
@ -1,44 +1,57 @@
|
||||
Building FRR on NetBSD 7 from Git Source
|
||||
NetBSD 7
|
||||
========================================
|
||||
|
||||
NetBSD 7 restrictions:
|
||||
----------------------
|
||||
|
||||
- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``NetBSD``. MPLS requires a Linux Kernel
|
||||
(4.5 or higher). LDP can be built, but may have limited use without
|
||||
MPLS
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
::
|
||||
|
||||
sudo pkgin install git autoconf automake libtool gmake gawk openssl \
|
||||
pkg-config json-c python27 py27-test python35
|
||||
pkg-config json-c python27 py27-test python35 py-sphinx
|
||||
|
||||
Install SSL Root Certificates (for git https access):
|
||||
|
||||
::
|
||||
|
||||
sudo pkgin install mozilla-rootcerts
|
||||
sudo touch /etc/openssl/openssl.cnf
|
||||
sudo mozilla-rootcerts install
|
||||
|
||||
Select default Python and py.test
|
||||
|
||||
::
|
||||
|
||||
sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
|
||||
sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
------------------------------------------------
|
||||
---------------------------------------------
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -g 93 frrvty
|
||||
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
||||
-d /nonexistent -s /sbin/nologin frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -66,7 +79,11 @@ an example)
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo mkdir /usr/pkg/etc/frr
|
||||
sudo touch /usr/pkg/etc/frr/zebra.conf
|
||||
sudo touch /usr/pkg/etc/frr/bgpd.conf
|
||||
@ -81,23 +98,35 @@ an example)
|
||||
sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
|
||||
sudo chmod 640 /usr/pkg/etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/sysctl.conf`:
|
||||
Add the following lines to the end of ``/etc/sysctl.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Routing: We need to forward packets
|
||||
net.inet.ip.forwarding=1
|
||||
net.inet6.ip6.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl`` to apply the same config to the running
|
||||
system
|
||||
|
||||
Install rc.d init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
### Install rc.d init files
|
||||
cp pkgsrc/*.sh /etc/rc.d/
|
||||
chmod 555 /etc/rc.d/*.sh
|
||||
|
||||
### Enable FRR processes
|
||||
Enable FRR processes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(Enable the required processes only)
|
||||
|
||||
::
|
||||
|
||||
echo "zebra=YES" >> /etc/rc.conf
|
||||
echo "bgpd=YES" >> /etc/rc.conf
|
||||
echo "ospfd=YES" >> /etc/rc.conf
|
@ -1,14 +1,17 @@
|
||||
Building FRR on OmniOS (OpenSolaris) from Git Source
|
||||
OmniOS (OpenSolaris)
|
||||
====================================================
|
||||
|
||||
OmniOS restrictions:
|
||||
--------------------
|
||||
|
||||
- MPLS is not supported on `OmniOS` or `Solaris`. MPLS requires a Linux
|
||||
Kernel (4.5 or higher). LDP can be built, but may have limited use
|
||||
without MPLS
|
||||
- MPLS is not supported on ``OmniOS`` or ``Solaris``. MPLS requires a
|
||||
Linux Kernel (4.5 or higher). LDP can be built, but may have limited
|
||||
use without MPLS
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
routeadm -e ipv4-forwarding
|
||||
routeadm -e ipv6-forwarding
|
||||
@ -18,6 +21,8 @@ Install required packages
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
pkg install \
|
||||
developer/build/autoconf \
|
||||
developer/build/automake \
|
||||
@ -36,6 +41,8 @@ Add packages:
|
||||
|
||||
Add additional Solaris packages:
|
||||
|
||||
::
|
||||
|
||||
pkgadd -d http://get.opencsw.org/now
|
||||
/opt/csw/bin/pkgutil -U
|
||||
/opt/csw/bin/pkgutil -y -i texinfo
|
||||
@ -45,33 +52,50 @@ Add additional Solaris packages:
|
||||
|
||||
Add libjson to Solaris equivalent of ld.so.conf
|
||||
|
||||
::
|
||||
|
||||
crle -l /opt/csw/lib -u
|
||||
|
||||
Add pytest:
|
||||
|
||||
::
|
||||
|
||||
pip install pytest
|
||||
|
||||
Install Sphinx:::
|
||||
|
||||
pip install sphinx
|
||||
|
||||
Select Python 2.7 as default (required for pytest)
|
||||
|
||||
::
|
||||
|
||||
rm -f /usr/bin/python
|
||||
ln -s /opt/csw/bin/python2.7 /usr/bin/python
|
||||
|
||||
Fix PATH for all users and non-interactive sessions. Edit `/etc/default/login`
|
||||
and add the following default PATH:
|
||||
Fix PATH for all users and non-interactive sessions. Edit
|
||||
``/etc/default/login`` and add the following default PATH:
|
||||
|
||||
::
|
||||
|
||||
PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin:/opt/csw/bin
|
||||
|
||||
Edit `~/.profile` and add the following default PATH:
|
||||
Edit ``~/.profile`` and add the following default PATH:
|
||||
|
||||
::
|
||||
|
||||
PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin:/opt/csw/bin
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 93 frr
|
||||
sudo groupadd -g 94 frrvty
|
||||
@ -81,6 +105,8 @@ any packages**
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -111,7 +137,10 @@ an example)
|
||||
gmake check
|
||||
sudo gmake install
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
routeadm -e ipv4-forwarding
|
||||
routeadm -e ipv6-forwarding
|
@ -1,39 +1,52 @@
|
||||
Building FRR on OpenBSD 6 from Git Source
|
||||
OpenBSD 6
|
||||
=========================================
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Configure PKG_PATH
|
||||
Configure PKG\_PATH
|
||||
|
||||
::
|
||||
|
||||
export PKG_PATH=http://ftp5.usa.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(machine -a)/
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
pkg_add git autoconf-2.69p2 automake-1.15p0 libtool bison
|
||||
pkg_add gmake gawk dejagnu openssl json-c py-test
|
||||
pkg_add gmake gawk dejagnu openssl json-c py-test py-sphinx
|
||||
|
||||
Select Python2.7 as default (required for pytest)
|
||||
|
||||
::
|
||||
|
||||
ln -s /usr/local/bin/python2.7 /usr/local/bin/python
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr group and user
|
||||
Add frr group and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
groupadd -g 525 _frr
|
||||
groupadd -g 526 _frrvty
|
||||
useradd -g 525 -u 525 -c "FRR suite" -G _frrvty \
|
||||
-d /nonexistent -s /sbin/nologin _frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
export AUTOCONF_VERSION="2.69"
|
||||
@ -61,7 +74,10 @@ an example)
|
||||
gmake check
|
||||
doas gmake install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
doas mkdir /var/frr
|
||||
doas chown _frr:_frr /var/frr
|
||||
@ -83,9 +99,12 @@ an example)
|
||||
doas chmod 750 /etc/frr
|
||||
doas chmod 640 /etc/frr/*.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to the end of `/etc/rc.conf`:
|
||||
Add the following lines to the end of ``/etc/rc.conf``:
|
||||
|
||||
::
|
||||
|
||||
net.inet6.ip6.forwarding=1 # 1=Permit forwarding of IPv6 packets
|
||||
net.inet6.ip6.mforwarding=1 # 1=Permit forwarding of IPv6 multicast packets
|
||||
@ -93,23 +112,34 @@ Add the following lines to the end of `/etc/rc.conf`:
|
||||
|
||||
**Reboot** to apply the config to the system
|
||||
|
||||
### Enable MPLS Forwarding
|
||||
Enable MPLS Forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To enable MPLS forwarding on a given interface, use the following command:
|
||||
To enable MPLS forwarding on a given interface, use the following
|
||||
command:
|
||||
|
||||
::
|
||||
|
||||
doas ifconfig em0 mpls
|
||||
|
||||
Alternatively, to make MPLS forwarding persistent across reboots, add the "mpls"
|
||||
keyword in the hostname.* files of the desired interfaces. Example:
|
||||
Alternatively, to make MPLS forwarding persistent across reboots, add
|
||||
the "mpls" keyword in the hostname.\* files of the desired interfaces.
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
cat /etc/hostname.em0
|
||||
inet 10.0.1.1 255.255.255.0 mpls
|
||||
|
||||
### Install rc.d init files
|
||||
Install rc.d init files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(create them in /etc/rc.d - no example are included at this time with
|
||||
FRR source)
|
||||
|
||||
Example (for zebra - store as `/etc/rc.d/frr_zebra.sh`)
|
||||
Example (for zebra - store as ``/etc/rc.d/frr_zebra.sh``)
|
||||
|
||||
::
|
||||
|
||||
#!/bin/sh
|
||||
#
|
||||
@ -121,9 +151,13 @@ Example (for zebra - store as `/etc/rc.d/frr_zebra.sh`)
|
||||
|
||||
rc_cmd $1
|
||||
|
||||
### Enable FRR processes
|
||||
Enable FRR processes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(Enable the required processes only)
|
||||
|
||||
::
|
||||
|
||||
echo "frr_zebra=YES" >> /etc/rc.conf
|
||||
echo "frr_bgpd=YES" >> /etc/rc.conf
|
||||
echo "frr_ospfd=YES" >> /etc/rc.conf
|
@ -1,22 +1,26 @@
|
||||
Building FRR on Ubuntu 12.04LTS from Git Source
|
||||
Ubuntu 12.04LTS
|
||||
===============================================
|
||||
|
||||
- MPLS is not supported on `Ubuntu 12.04` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
For an updated Ubuntu Kernel, see http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
- MPLS is not supported on ``Ubuntu 12.04`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
||||
texinfo libpam0g-dev dejagnu libjson0-dev pkg-config libpam0g-dev \
|
||||
libjson0-dev flex python-pip libc-ares-dev python3-dev
|
||||
libjson0-dev flex python-pip libc-ares-dev python3-dev python3-sphinx
|
||||
|
||||
Install newer bison from 14.04 package source (Ubuntu 12.04 package source
|
||||
is too old)
|
||||
Install newer bison from 14.04 package source (Ubuntu 12.04 package
|
||||
source is too old)
|
||||
|
||||
::
|
||||
|
||||
mkdir builddir
|
||||
cd builddir
|
||||
@ -35,6 +39,8 @@ is too old)
|
||||
|
||||
Install newer version of autoconf and automake:
|
||||
|
||||
::
|
||||
|
||||
wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
|
||||
tar xvf autoconf-2.69.tar.gz
|
||||
cd autoconf-2.69
|
||||
@ -53,15 +59,20 @@ Install newer version of autoconf and automake:
|
||||
|
||||
Install pytest:
|
||||
|
||||
::
|
||||
|
||||
pip install pytest
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
@ -69,10 +80,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -100,7 +115,10 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
@ -116,11 +134,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -129,18 +150,27 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
### Install the init.d service
|
||||
Install the init.d service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 tools/frr /etc/init.d/frr
|
||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
||||
sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
|
||||
### Enable daemons
|
||||
Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd.
|
||||
For example.
|
||||
Enable daemons
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||
those daemons you want to start by systemd.
|
||||
| For example.
|
||||
|
||||
::
|
||||
|
||||
zebra=yes
|
||||
bgpd=yes
|
||||
@ -150,6 +180,8 @@ For example.
|
||||
ripngd=yes
|
||||
isisd=yes
|
||||
|
||||
### Start the init.d service
|
||||
- /etc/init.d/frr start
|
||||
- use `/etc/init.d/frr status` to check its status.
|
||||
Start the init.d service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- /etc/init.d/frr start
|
||||
- use ``/etc/init.d/frr status`` to check its status.
|
@ -1,27 +1,32 @@
|
||||
Building FRR on Ubuntu 14.04LTS from Git Source
|
||||
Ubuntu 14.04LTS
|
||||
===============================================
|
||||
|
||||
- MPLS is not supported on `Ubuntu 14.04` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
For an updated Ubuntu Kernel, see http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
||||
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
|
||||
python-pytest libc-ares-dev python3-dev
|
||||
python-pytest libc-ares-dev python3-dev python3-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
@ -29,10 +34,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -61,7 +70,10 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
@ -77,11 +89,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IP & IPv6 forwarding
|
||||
Enable IP & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -90,19 +105,24 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
### Install the init.d service
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system ### Install the init.d service
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 tools/frr /etc/init.d/frr
|
||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
||||
sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
|
||||
Enable daemons
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
### Enable daemons
|
||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||
those daemons you want to start by systemd.
|
||||
| For example.
|
||||
|
||||
Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd.
|
||||
For example.
|
||||
::
|
||||
|
||||
zebra=yes
|
||||
bgpd=yes
|
||||
@ -112,8 +132,8 @@ For example.
|
||||
ripngd=yes
|
||||
isisd=yes
|
||||
|
||||
### Start the init.d service
|
||||
- /etc/init.d/frr start
|
||||
- use `/etc/init.d/frr status` to check its status.
|
||||
|
||||
Start the init.d service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- /etc/init.d/frr start
|
||||
- use ``/etc/init.d/frr status`` to check its status.
|
@ -1,28 +1,33 @@
|
||||
Building FRR on Ubuntu 16.04LTS from Git Source
|
||||
Ubuntu 16.04LTS
|
||||
===============================================
|
||||
|
||||
- MPLS is not supported on `Ubuntu 16.04` with default kernel. MPLS requires
|
||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
||||
without MPLS)
|
||||
For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
|
||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||
|
||||
Install required packages
|
||||
-------------------------
|
||||
|
||||
Add packages:
|
||||
|
||||
::
|
||||
|
||||
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
||||
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
|
||||
python-pytest libc-ares-dev python3-dev libsystemd-dev python-ipaddr
|
||||
python-pytest libc-ares-dev python3-dev libsystemd-dev python-ipaddr \
|
||||
python3-sphinx
|
||||
|
||||
Get FRR, compile it and install it (from Git)
|
||||
---------------------------------------------
|
||||
|
||||
**This assumes you want to build and install FRR from source and not using
|
||||
any packages**
|
||||
**This assumes you want to build and install FRR from source and not
|
||||
using any packages**
|
||||
|
||||
### Add frr groups and user
|
||||
Add frr groups and user
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo groupadd -g 92 frr
|
||||
sudo groupadd -r -g 85 frrvty
|
||||
@ -30,10 +35,14 @@ any packages**
|
||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||
sudo usermod -a -G frrvty frr
|
||||
|
||||
### Download Source, configure and compile it
|
||||
Download Source, configure and compile it
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(You may prefer different options on configure statement. These are just
|
||||
an example.)
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/frrouting/frr.git frr
|
||||
cd frr
|
||||
./bootstrap.sh
|
||||
@ -62,7 +71,10 @@ an example.)
|
||||
make check
|
||||
sudo make install
|
||||
|
||||
### Create empty FRR configuration files
|
||||
Create empty FRR configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||
@ -78,11 +90,14 @@ an example.)
|
||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
||||
|
||||
### Enable IPv4 & IPv6 forwarding
|
||||
Enable IPv4 & IPv6 forwarding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
||||
other settings)
|
||||
|
||||
::
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
@ -91,10 +106,14 @@ other settings)
|
||||
# based on Router Advertisements for this host
|
||||
net.ipv6.conf.all.forwarding=1
|
||||
|
||||
### Enable MPLS Forwarding (with Linux Kernel >= 4.5)
|
||||
Enable MPLS Forwarding (with Linux Kernel >= 4.5)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/sysctl.conf` and the following lines. Make sure to add a line
|
||||
equal to `net.mpls.conf.eth0.input` or each interface used with MPLS
|
||||
Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
|
||||
line equal to ``net.mpls.conf.eth0.input`` or each interface used with
|
||||
MPLS
|
||||
|
||||
::
|
||||
|
||||
# Enable MPLS Label processing on all interfaces
|
||||
net.mpls.conf.eth0.input=1
|
||||
@ -102,18 +121,24 @@ equal to `net.mpls.conf.eth0.input` or each interface used with MPLS
|
||||
net.mpls.conf.eth2.input=1
|
||||
net.mpls.platform_labels=100000
|
||||
|
||||
### Add MPLS kernel modules
|
||||
Add MPLS kernel modules
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add the following lines to `/etc/modules-load.d/modules.conf`:
|
||||
Add the following lines to ``/etc/modules-load.d/modules.conf``:
|
||||
|
||||
::
|
||||
|
||||
# Load MPLS Kernel Modules
|
||||
mpls-router
|
||||
mpls-iptunnel
|
||||
|
||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||
system
|
||||
|
||||
Install the systemd service (if rebooted from last step, change directory back to frr directory)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Install the systemd service (if rebooted from last step, change directory back to frr directory)
|
||||
::
|
||||
|
||||
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
|
||||
sudo install -m 644 tools/etc/default/frr /etc/default/frr
|
||||
@ -122,10 +147,14 @@ Add the following lines to `/etc/modules-load.d/modules.conf`:
|
||||
sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||
|
||||
### Enable daemons
|
||||
Enable daemons
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Edit `/etc/frr/daemons` and change the value from "no" to "yes" for those daemons you want to start by systemd.
|
||||
For example.
|
||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||
those daemons you want to start by systemd.
|
||||
| For example.
|
||||
|
||||
::
|
||||
|
||||
zebra=yes
|
||||
bgpd=yes
|
||||
@ -135,9 +164,13 @@ For example.
|
||||
ripngd=yes
|
||||
isisd=yes
|
||||
|
||||
### Enable the systemd service
|
||||
- systemctl enable frr
|
||||
Enable the systemd service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Start the systemd service
|
||||
- systemctl start frr
|
||||
- use `systemctl status frr` to check its status.
|
||||
- systemctl enable frr
|
||||
|
||||
Start the systemd service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- systemctl start frr
|
||||
- use ``systemctl status frr`` to check its status.
|
1
doc/developer/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../frr-sphinx.mk
|
8
doc/developer/bgpd.rst
Normal file
@ -0,0 +1,8 @@
|
||||
BGPD
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
next-hop-tracking
|
||||
|
22
doc/developer/building.rst
Normal file
@ -0,0 +1,22 @@
|
||||
Building FRR
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Building_FRR_on_LEDE-OpenWRT
|
||||
Building_FRR_on_CentOS6
|
||||
Building_FRR_on_CentOS7
|
||||
Building_FRR_on_Debian8
|
||||
Building_FRR_on_Debian9
|
||||
Building_FRR_on_Fedora24
|
||||
Building_FRR_on_FreeBSD10
|
||||
Building_FRR_on_FreeBSD11
|
||||
Building_FRR_on_FreeBSD9
|
||||
Building_FRR_on_NetBSD6
|
||||
Building_FRR_on_NetBSD7
|
||||
Building_FRR_on_OmniOS
|
||||
Building_FRR_on_OpenBSD6
|
||||
Building_FRR_on_Ubuntu1204
|
||||
Building_FRR_on_Ubuntu1404
|
||||
Building_FRR_on_Ubuntu1604
|
723
doc/developer/cli.rst
Normal file
@ -0,0 +1,723 @@
|
||||
Command Line Interface
|
||||
======================
|
||||
|
||||
FRR features a flexible modal command line interface. Often when adding new
|
||||
features or modifying existing code it is necessary to create or modify CLI
|
||||
commands. FRR has a powerful internal CLI system that does most of the heavy
|
||||
lifting for you.
|
||||
|
||||
All definitions for the CLI system are exposed in ``lib/command.h``. In this
|
||||
header there are a set of macros used to define commands. These macros are
|
||||
collectively referred to as "DEFUNs", because of their syntax:
|
||||
|
||||
::
|
||||
|
||||
DEFUN(command_name,
|
||||
command_name_cmd,
|
||||
"example command FOO...",
|
||||
"Examples\n"
|
||||
"CLI command\n"
|
||||
"Argument\n")
|
||||
{
|
||||
// ...command handler...
|
||||
}
|
||||
|
||||
DEFUNs generally take four arguments which are expanded into the appropriate
|
||||
constructs for hooking into the CLI. In order these are:
|
||||
|
||||
- **Function name** - the name of the handler function for the command
|
||||
- **Command name** - the identifier of the ``struct cmd_element`` for the
|
||||
command. By convention this should be the function name with ``_cmd``
|
||||
appended.
|
||||
- **Command definition** - an expression in FRR's CLI grammar that defines the
|
||||
form of the command and its arguments, if any
|
||||
- **Doc string** - a newline-delimited string that documents each element in
|
||||
the command definition
|
||||
|
||||
In the above example, ``command_name`` is the function name,
|
||||
``command_name_cmd`` is the command name, ``"example..."`` is the definition
|
||||
and the last argument is the doc string. The block following the macro is the
|
||||
body of the handler function, details on which are presented later in this
|
||||
section.
|
||||
|
||||
In order to make the command show up to the user it must be installed into the
|
||||
CLI graph. To do this, call:
|
||||
|
||||
``install_element(NODE, &command_name_cmd);``
|
||||
|
||||
This will install the command into the specified CLI node. Usually these calls
|
||||
are grouped together in a CLI initialization function for a set of commands,
|
||||
and the DEFUNs themselves are grouped into the same source file to avoid
|
||||
cluttering the codebase. The names of these files follow the form
|
||||
``*_vty.[ch]`` by convention. Please do not scatter individual CLI commands in
|
||||
the middle of source files; instead expose the necessary functions in a header
|
||||
and place the command definition in a ``*_vty.[ch]`` file.
|
||||
|
||||
Definition Grammar
|
||||
------------------
|
||||
|
||||
FRR uses its own grammar for defining CLI commands. The grammar draws from
|
||||
syntax commonly seen in \*nix manpages and should be fairly intuitive. The
|
||||
parser is implemented in Bison and the lexer in Flex. These may be found in
|
||||
``lib/command_lex.l`` and ``lib/command_parse.y``, respectively.
|
||||
|
||||
**ProTip**: if you define a new command and find that the parser is
|
||||
throwing syntax or other errors, the parser is the last place you want
|
||||
to look. Bison is very stable and if it detects a syntax error, 99% of
|
||||
the time it will be a syntax error in your definition.
|
||||
|
||||
The formal grammar in BNF is given below. This is the grammar implemented in
|
||||
the Bison parser. At runtime, the Bison parser reads all of the CLI strings and
|
||||
builds a combined directed graph that is used to match and interpret user
|
||||
input.
|
||||
|
||||
Human-friendly explanations of how to use this grammar are given a bit later in
|
||||
this section alongside information on the :ref:`cli-data-structures` constructed
|
||||
by the parser.
|
||||
|
||||
.. productionlist::
|
||||
command: `cmd_token_seq`
|
||||
: `cmd_token_seq` `placeholder_token` "..."
|
||||
cmd_token_seq: *empty*
|
||||
: `cmd_token_seq` `cmd_token`
|
||||
cmd_token: `simple_token`
|
||||
: `selector`
|
||||
simple_token: `literal_token`
|
||||
: `placeholder_token`
|
||||
literal_token: WORD `varname_token`
|
||||
varname_token: "$" WORD
|
||||
placeholder_token: `placeholder_token_real` `varname_token`
|
||||
placeholder_token_real: IPV4
|
||||
: IPV4_PREFIX
|
||||
: IPV6
|
||||
: IPV6_PREFIX
|
||||
: VARIABLE
|
||||
: RANGE
|
||||
: MAC
|
||||
: MAC_PREFIX
|
||||
selector: "<" `selector_seq_seq` ">" `varname_token`
|
||||
: "{" `selector_seq_seq` "}" `varname_token`
|
||||
: "[" `selector_seq_seq` "]" `varname_token`
|
||||
selector_seq_seq: `selector_seq_seq` "|" `selector_token_seq`
|
||||
: `selector_token_seq`
|
||||
selector_token_seq: `selector_token_seq` `selector_token`
|
||||
: `selector_token`
|
||||
selector_token: `selector`
|
||||
: `simple_token`
|
||||
|
||||
Tokens
|
||||
~~~~~~
|
||||
The various capitalized tokens in the BNF above are in fact themselves
|
||||
placeholders, but not defined as such in the formal grammar; the grammar
|
||||
provides the structure, and the tokens are actually more like a type system for
|
||||
the strings you write in your CLI definitions. A CLI definition string is
|
||||
broken apart and each piece is assigned a type by the lexer based on a set of
|
||||
regular expressions. The parser uses the type information to verify the string
|
||||
and determine the structure of the CLI graph; additional metadata (such as the
|
||||
raw text of each token) is encoded into the graph as it is constructed by the
|
||||
parser, but this is merely a dumb copy job.
|
||||
|
||||
Here is a brief summary of the various token types along with examples.
|
||||
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| Token type | Syntax | Description |
|
||||
+=================+=================+=============================================================+
|
||||
| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``MAC`` | ``M:A:C`` | Matches a 48-bit mac address. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``MAC_PREFIX`` | ``M:A:C/M`` | Matches a 48-bit mac address with a mask. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
|
||||
+-----------------+-----------------+-------------------------------------------------------------+
|
||||
|
||||
When presented with user input, the parser will search over all defined
|
||||
commands in the current context to find a match. It is aware of the various
|
||||
types of user input and has a ranking system to help disambiguate commands. For
|
||||
instance, suppose the following commands are defined in the user's current
|
||||
context:
|
||||
|
||||
::
|
||||
|
||||
example command FOO
|
||||
example command (22-49)
|
||||
example command A.B.C.D/X
|
||||
|
||||
The following table demonstrates the matcher's choice for a selection of
|
||||
possible user input.
|
||||
|
||||
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||
| Input | Matched command | Reason |
|
||||
+=============================+===========================+==============================================================================================================+
|
||||
| example command eLi7eH4xx0r | example command FOO | ``eLi7eH4xx0r`` is not an integer or IPv4 prefix, |
|
||||
| | | but FOO is a variable and matches all input. |
|
||||
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||
| example command 42 | example command (22-49) | ``42`` is not an IPv4 prefix. It does match both |
|
||||
| | | ``(22-49)`` and ``FOO``, but RANGE tokens are more specific and have a higher priority than VARIABLE tokens. |
|
||||
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||
| example command 10.3.3.0/24 | example command A.B.C.D/X | The user entered an IPv4 prefix, which is best matched by the last command. |
|
||||
+-----------------------------+---------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Rules
|
||||
~~~~~
|
||||
|
||||
There are also constructs which allow optional tokens, mutual exclusion, one-or-more selection and repetition.
|
||||
|
||||
- ``<angle|brackets>`` -- Contain sequences of tokens separated by pipes and
|
||||
provide mutual exclusion. User input matches at most one option.
|
||||
- ``[square brackets]`` -- Contains sequences of tokens that can be omitted.
|
||||
``[<a|b>]`` can be shortened to ``[a|b]``.
|
||||
- ``{curly|braces}`` -- similar to angle brackets, but instead of mutual
|
||||
exclusion, curly braces indicate that one or more of the pipe-separated
|
||||
sequences may be provided in any order.
|
||||
- ``VARIADICS...`` -- Any token which accepts input (anything except WORD)
|
||||
which occurs as the last token of a line may be followed by an ellipsis,
|
||||
which indicates that input matching the token may be repeated an unlimited
|
||||
number of times.
|
||||
- ``$name`` -- Specify a variable name for the preceding token. See
|
||||
"Variable Names" below.
|
||||
|
||||
Some general notes:
|
||||
|
||||
- Options are allowed at the beginning of the command. The developer is
|
||||
entreated to use these extremely sparingly. They are most useful for
|
||||
implementing the 'no' form of configuration commands. Please think carefully
|
||||
before using them for anything else. There is usually a better solution, even
|
||||
if it is just separating out the command definition into separate ones.
|
||||
- The developer should judiciously apply separation of concerns when defining
|
||||
commands. CLI definitions for two unrelated or vaguely related commands or
|
||||
configuration items should be defined in separate commands. Clarity is
|
||||
preferred over LOC (within reason).
|
||||
- The maximum number of space-separated tokens that can be entered is
|
||||
presently limited to 256. Please keep this limit in mind when
|
||||
implementing new CLI.
|
||||
|
||||
Variable Names
|
||||
--------------
|
||||
|
||||
The parser tries to fill the "varname" field on each token. This can
|
||||
happen either manually or automatically. Manual specifications work by
|
||||
appending ``"$name"`` after the input specifier:
|
||||
|
||||
::
|
||||
|
||||
foo bar$cmd WORD$name A.B.C.D$ip
|
||||
|
||||
Note that you can also assign variable names to fixed input tokens, this
|
||||
can be useful if multiple commands share code. You can also use "$name"
|
||||
after a multiple-choice option:
|
||||
|
||||
::
|
||||
|
||||
foo bar <A.B.C.D|X:X::X:X>$addr [optionA|optionB]$mode
|
||||
|
||||
The variable name is in this case assigned to the last token in each of
|
||||
the branches.
|
||||
|
||||
Automatic assignment of variable names works by applying the following
|
||||
rules:
|
||||
|
||||
- manual names always have priority
|
||||
- a "[no]" at the beginning receives "no" as varname on the "no" token
|
||||
- VARIABLE tokens whose text is not "WORD" or "NAME" receive a cleaned
|
||||
lowercase version of the token text as varname, e.g. "ROUTE-MAP"
|
||||
becomes "route\_map".
|
||||
- other variable tokens (i.e. everything except "fixed") receive the
|
||||
text of the preceding fixed token as varname, if one can be found.
|
||||
E.g.: "ip route A.B.C.D/M INTERFACE" assigns "route" to the
|
||||
"A.B.C.D/M" token.
|
||||
|
||||
These rules should make it possible to avoid manual varname assignment
|
||||
in 90% of the cases.
|
||||
|
||||
DEFPY
|
||||
-----
|
||||
|
||||
``DEFPY(...)`` is an enhanced version of ``DEFUN()`` which is
|
||||
preprocessed by ``python/clidef.py``. The python script parses the
|
||||
command definition string, extracts variable names and types, and
|
||||
generates a C wrapper function that parses the variables and passes them
|
||||
on. This means that in the CLI function body, you will receive
|
||||
additional parameters with appropriate types.
|
||||
|
||||
This is best explained by an example:
|
||||
|
||||
::
|
||||
|
||||
DEFPY(func, func_cmd, "[no] foo bar A.B.C.D (0-99)$num", "...help...")
|
||||
|
||||
=>
|
||||
|
||||
func(self, vty, argc, argv, /* standard CLI arguments */
|
||||
|
||||
const char *no, /* unparsed "no" */
|
||||
struct in_addr bar, /* parsed IP address */
|
||||
const char *bar_str, /* unparsed IP address */
|
||||
long num, /* parsed num */
|
||||
const char *num_str) /* unparsed num */
|
||||
|
||||
Note that as documented in the previous section, "bar" is automatically
|
||||
applied as variable name for "A.B.C.D". The python code then detects
|
||||
this is an IP address argument and generates code to parse it into a
|
||||
``struct in_addr``, passing it in ``bar``. The raw value is passed in
|
||||
``bar_str``. The range/number argument works in the same way with the
|
||||
explicitly given variable name.
|
||||
|
||||
Type rules
|
||||
~~~~~~~~~~
|
||||
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| Token(s) | Type | Value if omitted by user |
|
||||
+=============================+================================+==========================+
|
||||
| ``A.B.C.D`` | ``struct in_addr`` | 0.0.0.0 |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``X:X::X:X`` | ``struct in6_addr`` | \:: |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``A.B.C.D + X:X::X:X`` | ``const union sockunion *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``A.B.C.D/M`` | ``const struct prefix_ipv4 *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``X:X::X:X/M`` | ``const struct prefix_ipv6 *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``A.B.C.D/M + X:X::X:X/M`` | ``const struct prefix *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``(0-9)`` | ``long`` | 0 |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``VARIABLE`` | ``const char *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| ``word`` | ``const char *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
| *all other* | ``const char *`` | NULL |
|
||||
+-----------------------------+--------------------------------+--------------------------+
|
||||
|
||||
Note the following details:
|
||||
|
||||
- Not all parameters are pointers, some are passed as values.
|
||||
- When the type is not ``const char *``, there will be an extra
|
||||
``_str`` argument with type ``const char *``.
|
||||
- You can give a variable name not only to ``VARIABLE`` tokens but also
|
||||
to ``word`` tokens (e.g. constant words). This is useful if some
|
||||
parts of a command are optional. The type will be ``const char *``.
|
||||
- ``[no]`` will be passed as ``const char *no``.
|
||||
- Pointers will be NULL when the argument is optional and the user did
|
||||
not use it.
|
||||
- If a parameter is not a pointer, but is optional and the user didn't
|
||||
use it, the default value will be passed. Check the ``_str`` argument
|
||||
if you need to determine whether the parameter was omitted.
|
||||
- If the definition contains multiple parameters with the same variable
|
||||
name, they will be collapsed into a single function parameter. The
|
||||
python code will detect if the types are compatible (i.e. IPv4 + IPv6
|
||||
variantes) and choose a corresponding C type.
|
||||
- The standard DEFUN parameters (self, vty, argc, argv) are still
|
||||
present and can be used. A DEFUN can simply be **edited into a DEFPY
|
||||
without further changes and it will still work**; this allows easy
|
||||
forward migration.
|
||||
- A file may contain both DEFUN and DEFPY statements.
|
||||
|
||||
Getting a parameter dump
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The clidef.py script can be called to get a list of DEFUNs/DEFPYs with
|
||||
the parameter name/type list:
|
||||
|
||||
::
|
||||
|
||||
lib/clippy python/clidef.py --all-defun --show lib/plist.c > /dev/null
|
||||
|
||||
The generated code is printed to stdout, the info dump to stderr. The
|
||||
``--all-defun`` argument will make it process DEFUN blocks as well as
|
||||
DEFPYs, which is useful prior to converting some DEFUNs. **The dump does
|
||||
not list the ``_str`` arguments** to keep the output shorter.
|
||||
|
||||
Note that the clidef.py script cannot be run with python directly, it
|
||||
needs to be run with *clippy* since the latter makes the CLI parser
|
||||
available.
|
||||
|
||||
Include & Makefile requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A source file that uses DEFPY needs to include the ``_clippy.c`` file
|
||||
**before all DEFPY statements**:
|
||||
|
||||
::
|
||||
|
||||
/* GPL header */
|
||||
#include ...
|
||||
|
||||
...
|
||||
|
||||
#include "daemon/filename_clippy.c"
|
||||
|
||||
DEFPY(...)
|
||||
DEFPY(...)
|
||||
|
||||
install_element(...)
|
||||
|
||||
This dependency needs to be marked in Makefile.am: (there is no ordering
|
||||
requirement)
|
||||
|
||||
::
|
||||
|
||||
include ../common.am
|
||||
|
||||
# ...
|
||||
|
||||
# if linked into a LTLIBRARY (.la/.so):
|
||||
filename.lo: filename_clippy.c
|
||||
|
||||
# if linked into an executable or static library (.a):
|
||||
filename.o: filename_clippy.c
|
||||
|
||||
Doc Strings
|
||||
-----------
|
||||
|
||||
Each token in a command definition should be documented with a brief doc string
|
||||
that informs a user of the meaning and/or purpose of the subsequent command
|
||||
tree. These strings are provided as the last parameter to DEFUN macros,
|
||||
concatenated together and separated by an escaped newline (\n). These are best
|
||||
explained by example.
|
||||
|
||||
::
|
||||
|
||||
DEFUN (config_terminal,
|
||||
config_terminal_cmd,
|
||||
"configure terminal",
|
||||
"Configuration from vty interface\n"
|
||||
"Configuration terminal\n")
|
||||
|
||||
The last parameter is split into two lines for readability. Two newline
|
||||
delimited doc strings are present, one for each token in the command.
|
||||
The second string documents the functionality of the 'terminal' command
|
||||
in the 'configure' tree.
|
||||
|
||||
Note that the first string, for 'configure' does not contain
|
||||
documentation for 'terminal'. This is because the CLI is best envisioned
|
||||
as a tree, with tokens defining branches. An imaginary 'start' token is
|
||||
the root of every command in a CLI node. Each subsequent written token
|
||||
descends into a subtree, so the documentation for that token ideally
|
||||
summarizes all the functionality contained in the subtree.
|
||||
|
||||
A consequence of this structure is that the developer must be careful to
|
||||
use the same doc strings when defining multiple commands that are part
|
||||
of the same tree. Commands which share prefixes must share the same doc
|
||||
strings for those prefixes. On startup the parser will generate warnings
|
||||
if it notices inconsistent doc strings. Behavior is undefined; the same
|
||||
token may show up twice in completions, with different doc strings, or
|
||||
it may show up once with a random doc string. Parser warnings should be
|
||||
heeded and fixed to avoid confusing users.
|
||||
|
||||
The number of doc strings provided must be equal to the amount of tokens
|
||||
present in the command definition, read left to right, ignoring any
|
||||
special constructs.
|
||||
|
||||
In the examples below, each arrowed token needs a doc string.
|
||||
|
||||
::
|
||||
|
||||
"show ip bgp"
|
||||
^ ^ ^
|
||||
|
||||
"command <foo|bar> [example]"
|
||||
^ ^ ^ ^
|
||||
|
||||
.. _cli-data-structures:
|
||||
|
||||
Data Structures
|
||||
---------------
|
||||
|
||||
On startup, the CLI parser sequentially parses each command string
|
||||
definition and constructs a directed graph with each token forming a
|
||||
node. This graph is the basis of the entire CLI system. It is used to
|
||||
match user input in order to generate command completions and match
|
||||
commands to functions.
|
||||
|
||||
There is one graph per CLI node (not the same as a graph node in the CLI
|
||||
graph). The CLI node struct keeps a reference to its graph (see
|
||||
lib/command.h).
|
||||
|
||||
While most of the graph maintains the form of a tree, special constructs
|
||||
outlined in the Rules section introduce some quirks. <>, [] and {} form
|
||||
self-contained 'subgraphs'. Each subgraph is a tree except that all of
|
||||
the 'leaves' actually share a child node. This helps with minimizing
|
||||
graph size and debugging.
|
||||
|
||||
As a working example, here is the graph of the following command: ::
|
||||
|
||||
show [ip] bgp neighbors [<A.B.C.D|X:X::X:X|WORD>] [json]
|
||||
|
||||
.. figure:: ../figures/cligraph.svg
|
||||
:align: center
|
||||
|
||||
Graph of example CLI command
|
||||
|
||||
|
||||
``FORK`` and ``JOIN`` nodes are plumbing nodes that don't correspond to user
|
||||
input. They're necessary in order to deduplicate these constructs where
|
||||
applicable.
|
||||
|
||||
Options follow the same form, except that there is an edge from the ``FORK``
|
||||
node to the ``JOIN`` node. Since all of the subgraphs in the example command
|
||||
are optional, all of them have this edge.
|
||||
|
||||
Keywords follow the same form, except that there is an edge from ``JOIN`` to
|
||||
``FORK``. Because of this the CLI graph cannot be called acyclic. There is
|
||||
special logic in the input matching code that keeps a stack of paths already
|
||||
taken through the node in order to disallow following the same path more than
|
||||
once.
|
||||
|
||||
Variadics are a bit special; they have an edge back to themselves, which allows
|
||||
repeating the same input indefinitely.
|
||||
|
||||
The leaves of the graph are nodes that have no out edges. These nodes are
|
||||
special; their data section does not contain a token, as most nodes do, or
|
||||
NULL, as in ``FORK``/``JOIN`` nodes, but instead has a pointer to a
|
||||
cmd\_element. All paths through the graph that terminate on a leaf are
|
||||
guaranteed to be defined by that command. When a user enters a complete
|
||||
command, the command matcher tokenizes the input and executes a DFS on the CLI
|
||||
graph. If it is simultaneously able to exhaust all input (one input token per
|
||||
graph node), and then find exactly one leaf connected to the last node it
|
||||
reaches, then the input has matched the corresponding command and the command
|
||||
is executed. If it finds more than one node, then the command is ambiguous
|
||||
(more on this in deduplication). If it cannot exhaust all input, the command is
|
||||
unknown. If it exhausts all input but does not find an edge node, the command
|
||||
is incomplete.
|
||||
|
||||
The parser uses an incremental strategy to build the CLI graph for a node. Each
|
||||
command is parsed into its own graph, and then this graph is merged into the
|
||||
overall graph. During this merge step, the parser makes a best-effort attempt
|
||||
to remove duplicate nodes. If it finds a node in the overall graph that is
|
||||
equal to a node in the corresponding position in the command graph, it will
|
||||
intelligently merge the properties from the node in the command graph into the
|
||||
already-existing node. Subgraphs are also checked for isomorphism and merged
|
||||
where possible. The definition of whether two nodes are 'equal' is based on the
|
||||
equality of some set of token properties; read the parser source for the most
|
||||
up-to-date definition of equality.
|
||||
|
||||
When the parser is unable to deduplicate some complicated constructs, this can
|
||||
result in two identical paths through separate parts of the graph. If this
|
||||
occurs and the user enters input that matches these paths, they will receive an
|
||||
'ambiguous command' error and will be unable to execute the command. Most of
|
||||
the time the parser can detect and warn about duplicate commands, but it will
|
||||
not always be able to do this. Hence care should be taken before defining a
|
||||
new command to ensure it is not defined elsewhere.
|
||||
|
||||
Command handlers
|
||||
----------------
|
||||
|
||||
The block that follows a CLI definition is executed when a user enters
|
||||
input that matches the definition. Its function signature looks like
|
||||
this:
|
||||
|
||||
::
|
||||
|
||||
int (*func) (const struct cmd_element *, struct vty *, int, struct cmd_token *[]);
|
||||
|
||||
The first argument is the command definition struct. The last argument
|
||||
is an ordered array of tokens that correspond to the path taken through
|
||||
the graph, and the argument just prior to that is the length of the
|
||||
array.
|
||||
|
||||
The arrangement of the token array has changed from the prior
|
||||
incarnation of the CLI system. In the old system, missing arguments were
|
||||
padded with NULLs so that the same parts of a command would show up at
|
||||
the same indices regardless of what was entered. The new system does not
|
||||
perform such padding and therefore it is generally *incorrect* to assume
|
||||
consistent indices in this array. As a simple example:
|
||||
|
||||
Command definition:
|
||||
|
||||
::
|
||||
|
||||
command [foo] <bar|baz>
|
||||
|
||||
User enters:
|
||||
|
||||
::
|
||||
|
||||
command foo bar
|
||||
|
||||
Array:
|
||||
|
||||
::
|
||||
|
||||
[0] -> command
|
||||
[1] -> foo
|
||||
[2] -> bar
|
||||
|
||||
User enters:
|
||||
|
||||
::
|
||||
|
||||
command baz
|
||||
|
||||
Array:
|
||||
|
||||
::
|
||||
|
||||
[0] -> command
|
||||
[1] -> baz
|
||||
|
||||
Command abbreviation & matching priority
|
||||
----------------------------------------
|
||||
|
||||
As in the prior implementation, it is possible for users to elide parts
|
||||
of tokens when the CLI matcher does not need them to make an unambiguous
|
||||
match. This is best explained by example.
|
||||
|
||||
Command definitions:
|
||||
|
||||
::
|
||||
|
||||
command dog cow
|
||||
command dog crow
|
||||
|
||||
User input:
|
||||
|
||||
::
|
||||
|
||||
c d c -> ambiguous command
|
||||
c d co -> match "command dog cow"
|
||||
|
||||
In the new implementation, this functionality has improved. Where
|
||||
previously the parser would stop at the first ambiguous token, it will
|
||||
now look ahead and attempt to disambiguate based on tokens later on in
|
||||
the input string.
|
||||
|
||||
Command definitions:
|
||||
|
||||
::
|
||||
|
||||
show ip bgp A.B.C.D
|
||||
show ipv6 bgp X:X::X:X
|
||||
|
||||
User enters:
|
||||
|
||||
::
|
||||
|
||||
s i b 4.3.2.1 -> match "show ip bgp A.B.C.D"
|
||||
s i b ::e0 -> match "show ipv6 bgp X:X::X:X"
|
||||
|
||||
Previously both of these commands would be ambiguous since 'i' does not
|
||||
explicitly select either 'ip' or 'ipv6'. However, since the user later
|
||||
provides a token that matches only one of the commands (an IPv4 or IPv6
|
||||
address) the parser is able to look ahead and select the appropriate
|
||||
command. This has some implications for parsing the argv\*[] that is
|
||||
passed to the command handler.
|
||||
|
||||
Now consider a command definition such as:
|
||||
|
||||
::
|
||||
|
||||
command <foo|VAR>
|
||||
|
||||
'foo' only matches the string 'foo', but 'VAR' matches any input,
|
||||
including 'foo'. Who wins? In situations like this the matcher will
|
||||
always choose the 'better' match, so 'foo' will win.
|
||||
|
||||
Consider also:
|
||||
|
||||
::
|
||||
|
||||
show <ip|ipv6> foo
|
||||
|
||||
User input:
|
||||
|
||||
::
|
||||
|
||||
show ip foo
|
||||
|
||||
'ip' partially matches 'ipv6' but exactly matches 'ip', so 'ip' will
|
||||
win.
|
||||
|
||||
struct cmd\_token
|
||||
-----------------
|
||||
|
||||
::
|
||||
|
||||
/* Command token struct. */
|
||||
struct cmd_token
|
||||
{
|
||||
enum cmd_token_type type; // token type
|
||||
u_char attr; // token attributes
|
||||
bool allowrepeat; // matcher allowed to match token repetitively?
|
||||
|
||||
char *text; // token text
|
||||
char *desc; // token description
|
||||
long long min, max; // for ranges
|
||||
char *arg; // user input that matches this token
|
||||
char *varname; // variable name
|
||||
};
|
||||
|
||||
This struct is used in the CLI graph to match input against. It is also
|
||||
used to pass user input to command handler functions, as it is
|
||||
frequently useful for handlers to have access to that information. When
|
||||
a command is matched, the sequence of cmd\_tokens that form the matching
|
||||
path are duplicated and placed in order into argv\*[]. Before this
|
||||
happens the ->arg field is set to point at the snippet of user input
|
||||
that matched it.
|
||||
|
||||
For most nontrivial commands the handler function will need to determine
|
||||
which of the possible matching inputs was entered. Previously this was
|
||||
done by looking at the first few characters of input. This is now
|
||||
considered an anti-pattern and should be avoided. Instead, the ->type or
|
||||
->text fields for this logic. The ->type field can be used when the
|
||||
possible inputs differ in type. When the possible types are the same,
|
||||
use the ->text field. This field has the full text of the corresponding
|
||||
token in the definition string and using it makes for much more readable
|
||||
code. An example is helpful.
|
||||
|
||||
Command definition:
|
||||
|
||||
::
|
||||
|
||||
command <(1-10)|foo|BAR>
|
||||
|
||||
In this example, the user may enter any one of: \* an integer between 1
|
||||
and 10 \* "foo" \* anything at all
|
||||
|
||||
If the user enters "command f", then:
|
||||
|
||||
::
|
||||
|
||||
argv[1]->type == WORD_TKN
|
||||
argv[1]->arg == "f"
|
||||
argv[1]->text == "foo"
|
||||
|
||||
Range tokens have some special treatment; a token with ->type ==
|
||||
RANGE\_TKN will have the ->min and ->max fields set to the bounding
|
||||
values of the range.
|
||||
|
||||
Permutations
|
||||
------------
|
||||
|
||||
Finally, it is sometimes useful to check all the possible combinations
|
||||
of input that would match an arbitrary definition string. There is a
|
||||
tool in tools/ called 'permutations' that reads CLI definition strings
|
||||
on stdin and prints out all matching input permutations. It also dumps a
|
||||
text representation of the graph, which is more useful for debugging
|
||||
than anything else. It looks like this:
|
||||
|
||||
::
|
||||
|
||||
$ ./permutations "show [ip] bgp [<view|vrf> WORD]"
|
||||
|
||||
show ip bgp view WORD
|
||||
show ip bgp vrf WORD
|
||||
show ip bgp
|
||||
show bgp view WORD
|
||||
show bgp vrf WORD
|
||||
show bgp
|
||||
|
||||
This functionality is also built into VTY/VTYSH; the 'list permutations'
|
||||
command will list all possible matching input permutations in the
|
||||
current CLI node.
|
@ -24,7 +24,10 @@ import re
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
needs_sphinx = '1.0'
|
||||
|
||||
# prolog for various variable substitutions
|
||||
rst_prolog = ''
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
@ -36,7 +39,7 @@ templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
# source_suffix = ['.rst', '.md']
|
||||
# source_suffix = ['.rst']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
@ -59,14 +62,51 @@ version = u'?.?'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'?.?-?'
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Extract values from codebase for substitution into docs.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Various installation prefixes. Reasonable defaults are set where possible.
|
||||
# Values are overridden by logic below.
|
||||
replace_vars = {
|
||||
'AUTHORS': 'Kunihiro Ishiguro, et al.',
|
||||
'COPYRIGHT_YEAR': '1999-2005',
|
||||
'COPYRIGHT_STR': None,
|
||||
'PACKAGE_NAME': project.lower(),
|
||||
'PACKAGE_TARNAME': project.lower(),
|
||||
'PACKAGE_STRING': None,
|
||||
'PACKAGE_URL': 'https://frrouting.org/',
|
||||
'PACKAGE_VERSION': None,
|
||||
'INSTALL_PREFIX_ETC': None,
|
||||
'INSTALL_PREFIX_SBIN': None,
|
||||
'INSTALL_PREFIX_STATE': None,
|
||||
'INSTALL_PREFIX_MODULES': None,
|
||||
'INSTALL_USER': None,
|
||||
'INSTALL_GROUP': None,
|
||||
'INSTALL_VTY_GROUP': None,
|
||||
}
|
||||
|
||||
# extract version information, installation location, other stuff we need to
|
||||
# use when building final documents
|
||||
val = re.compile('^S\["([^"]+)"\]="(.*)"$')
|
||||
with open('../../config.status', 'r') as cfgstatus:
|
||||
for ln in cfgstatus.readlines():
|
||||
m = val.match(ln)
|
||||
if m is None: continue
|
||||
if m.group(1) == 'PACKAGE_VERSION':
|
||||
release = m.group(2)
|
||||
version = release.split('-')[0]
|
||||
if not m or m.group(1) not in replace_vars.keys(): continue
|
||||
replace_vars[m.group(1)] = m.group(2)
|
||||
|
||||
# manually fill out some of these we can't get from config.status
|
||||
replace_vars['COPYRIGHT_STR'] = "Copyright (c)"
|
||||
replace_vars['COPYRIGHT_STR'] += ' {0}'.format(replace_vars['COPYRIGHT_YEAR'])
|
||||
replace_vars['COPYRIGHT_STR'] += ' {0}'.format(replace_vars['AUTHORS'])
|
||||
release = replace_vars['PACKAGE_VERSION']
|
||||
version = release.split('-')[0]
|
||||
|
||||
# add substitutions to prolog
|
||||
for key, value in replace_vars.items():
|
||||
rst_prolog += '.. |{0}| replace:: {1}\n'.format(key, value)
|
||||
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@ -117,12 +157,14 @@ todo_include_todos = True
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
html_theme_options = {
|
||||
'sidebarbgcolor': '#374249'
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
@ -136,17 +178,17 @@ html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
html_logo = '../figures/frr-icon.svg'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
html_favicon = '../figures/frr-logo-icon.png'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
#html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
@ -231,13 +273,13 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'FRR.tex', u'FRR Documentation',
|
||||
(master_doc, 'FRR.tex', u"FRR Developer's Manual",
|
||||
u'FRR', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
latex_logo = '../figures/frr-logo-medium.png'
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
@ -261,7 +303,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'frr', u'FRR Documentation',
|
||||
(master_doc, 'frr', u"FRR Developer's Manual",
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
@ -275,7 +317,7 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'FRR', u'FRR Documentation',
|
||||
(master_doc, 'frr', u"FRR Developer's Manual",
|
||||
author, 'FRR', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
@ -291,3 +333,9 @@ texinfo_documents = [
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
# custom extensions here
|
||||
def setup(app):
|
||||
# object type for FRR CLI commands, can be extended to document parent CLI
|
||||
# node later on
|
||||
app.add_object_type('clicmd', 'clicmd')
|
@ -1,18 +1,13 @@
|
||||
Welcome to FRR's documentation!
|
||||
===============================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
workflow
|
||||
library
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
bgpd
|
||||
building
|
||||
ospf-api
|
||||
ospf-sr
|
||||
|
@ -6,5 +6,7 @@ libfrr library facilities
|
||||
|
||||
memtypes
|
||||
hooks
|
||||
cli
|
||||
modules
|
||||
|
||||
|
123
doc/developer/modules.rst
Normal file
@ -0,0 +1,123 @@
|
||||
Modules
|
||||
=======
|
||||
|
||||
FRR has facilities to load DSOs at startup via ``dlopen()``. These are used to
|
||||
implement modules, such as SNMP and FPM.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
- can't load, unload, or reload during runtime. This just needs some
|
||||
work and can probably be done in the future.
|
||||
- doesn't fix any of the "things need to be changed in the code in the
|
||||
library" issues. Most prominently, you can't add a CLI node because
|
||||
CLI nodes are listed in the library...
|
||||
- if your module crashes, the daemon crashes. Should be obvious.
|
||||
- **does not provide a stable API or ABI**. Your module must match a
|
||||
version of FRR and you may have to update it frequently to match
|
||||
changes.
|
||||
- **does not create a license boundary**. Your module will need to link
|
||||
libzebra and include header files from the daemons, meaning it will
|
||||
be GPL-encumbered.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Look for ``moduledir`` in ``configure.ac``, default is normally
|
||||
``/usr/lib64/frr/modules`` but depends on ``--libdir`` / ``--prefix``.
|
||||
|
||||
The daemon's name is prepended when looking for a module, e.g. "snmp"
|
||||
tries to find "zebra\_snmp" first when used in zebra. This is just to
|
||||
make it nicer for the user, with the snmp module having the same name
|
||||
everywhere.
|
||||
|
||||
Modules can be packaged separately from FRR. The SNMP and FPM modules
|
||||
are good candidates for this because they have dependencies (net-snmp /
|
||||
protobuf) that are not FRR dependencies. However, any distro packages
|
||||
should have an "exact-match" dependency onto the FRR package. Using a
|
||||
module from a different FRR version will probably blow up nicely.
|
||||
|
||||
For snapcraft (and during development), modules can be loaded with full
|
||||
path (e.g. -M ``$SNAP/lib/frr/modules/zebra_snmp.so``). Note that
|
||||
libtool puts output files in the .libs directory, so during development
|
||||
you have to use ``./zebra -M .libs/zebra_snmp.so``.
|
||||
|
||||
Creating a module
|
||||
-----------------
|
||||
|
||||
... best to look at the existing SNMP or FPM modules.
|
||||
|
||||
Basic boilerplate:
|
||||
|
||||
::
|
||||
|
||||
#include "hook.h"
|
||||
#include "module.h"
|
||||
|
||||
static int
|
||||
module_init (void)
|
||||
{
|
||||
hook_register(frr_late_init, module_late_init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FRR_MODULE_SETUP(
|
||||
.name = "my module",
|
||||
.version = "0.0",
|
||||
.description = "my module",
|
||||
.init = module_init,
|
||||
)
|
||||
|
||||
The ``frr_late_init`` hook will be called after the daemon has finished
|
||||
its other startup and is about to enter the main event loop; this is the
|
||||
best place for most initialisation.
|
||||
|
||||
Compiler & Linker magic
|
||||
-----------------------
|
||||
|
||||
There's a ``THIS_MODULE`` (like in the Linux kernel), which uses
|
||||
``visibility`` attributes to restrict it to the current module. If you
|
||||
get a linker error with ``_frrmod_this_module``, there is some linker
|
||||
SNAFU. This shouldn't be possible, though one way to get it would be to
|
||||
not include libzebra (which provides a fallback definition for the
|
||||
symbol).
|
||||
|
||||
libzebra and the daemons each have their own ``THIS_MODULE``, as do all
|
||||
loadable modules. In any other libraries (e.g. ``libfrrsnmp``),
|
||||
``THIS_MODULE`` will use the definition in libzebra; same applies if the
|
||||
main executable doesn't use ``FRR_DAEMON_INFO`` (e.g. all testcases).
|
||||
|
||||
The deciding factor here is "what dynamic linker unit are you using the
|
||||
symbol from." If you're in a library function and want to know who
|
||||
called you, you can't use ``THIS_MODULE`` (because that'll just tell you
|
||||
you're in the library). Put a macro around your function that adds
|
||||
``THIS_MODULE`` in the *caller's code calling your function*.
|
||||
|
||||
The idea is to use this in the future for module unloading. Hooks
|
||||
already remember which module they were installed by, as groundwork for
|
||||
a function that removes all of a module's installed hooks.
|
||||
|
||||
There's also the ``frr_module`` symbol in modules, pretty much a
|
||||
standard entry point for loadable modules.
|
||||
|
||||
Hooks
|
||||
-----
|
||||
|
||||
Hooks are just points in the code where you can register your callback
|
||||
to be called. The parameter list is specific to the hook point. Since
|
||||
there is no stable API, the hook code has some extra type safety checks
|
||||
making sure you get a compiler warning when the hook parameter list
|
||||
doesn't match your callback. Don't ignore these warnings.
|
||||
|
||||
Relation to MTYPE macros
|
||||
------------------------
|
||||
|
||||
The MTYPE macros, while primarily designed to decouple MTYPEs from the
|
||||
library and beautify the code, also work very nicely with loadable
|
||||
modules -- both constructors and destructors are executed when
|
||||
loading/unloading modules.
|
||||
|
||||
This means there is absolutely no change required to MTYPEs, you can
|
||||
just use them in a module and they will even clean up themselves when we
|
||||
implement module unloading and an unload happens. In fact, it's
|
||||
impossible to create a bug where unloading fails to de-register a MTYPE.
|
352
doc/developer/next-hop-tracking.rst
Normal file
@ -0,0 +1,352 @@
|
||||
Next Hop Tracking
|
||||
==================
|
||||
|
||||
Next hop tracking is an optimization feature that reduces the processing time
|
||||
involved in the BGP bestpath algorithm by monitoring changes to the routing
|
||||
table.
|
||||
|
||||
Background
|
||||
-----------
|
||||
|
||||
Recursive routes are of the form:
|
||||
|
||||
::
|
||||
|
||||
p/m --> n
|
||||
[Ex: 1.1.0.0/16 --> 2.2.2.2]
|
||||
|
||||
where 'n' itself is resolved through another route as follows:
|
||||
|
||||
::
|
||||
|
||||
p2/m --> h, interface
|
||||
[Ex: 2.2.2.0/24 --> 3.3.3.3, eth0]
|
||||
|
||||
Usually, BGP routes are recursive in nature and BGP nexthops get resolved
|
||||
through an IGP route. IGP usually adds its routes pointing to an interface
|
||||
(these are called non-recursive routes).
|
||||
|
||||
When BGP receives a recursive route from a peer, it needs to validate the
|
||||
nexthop. The path is marked valid or invalid based on the reachability status
|
||||
of the nexthop. Nexthop validation is also important for BGP decision process
|
||||
as the metric to reach the nexthop is a parameter to best path selection
|
||||
process.
|
||||
|
||||
As it goes with routing, this is a dynamic process. Route to the nexthop can
|
||||
change. The nexthop can become unreachable or reachable. In the current BGP
|
||||
implementation, the nexthop validation is done periodically in the scanner run.
|
||||
The default scanner run interval is one minute. Every minute, the scanner task
|
||||
walks the entire BGP table. It checks the validity of each nexthop with Zebra
|
||||
(the routing table manager) through a request and response message exchange
|
||||
between BGP and Zebra process. BGP process is blocked for that duration. The
|
||||
mechanism has two major drawbacks:
|
||||
|
||||
- The scanner task runs to completion. That can potentially starve the other
|
||||
tasks for long periods of time, based on the BGP table size and number of
|
||||
nexthops.
|
||||
|
||||
- Convergence around routing changes that affect the nexthops can be long
|
||||
(around a minute with the default intervals). The interval can be shortened
|
||||
to achieve faster reaction time, but it makes the first problem worse, with
|
||||
the scanner task consuming most of the CPU resources.
|
||||
|
||||
The next-hop tracking feature makes this process event-driven. It eliminates
|
||||
periodic nexthop validation and introduces an asynchronous communication path
|
||||
between BGP and Zebra for route change notifications that can then be acted
|
||||
upon.
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
Stating the obvious, the main goal is to remove the two limitations we
|
||||
discussed in the previous section. The goals, in a constructive tone,
|
||||
are the following:
|
||||
|
||||
- **Fairness**: the scanner run should not consume an unjustly high amount of
|
||||
CPU time. This should give an overall good performance and response time to
|
||||
other events (route changes, session events, IO/user interface).
|
||||
|
||||
- **Convergence**: BGP must react to nexthop changes instantly and provide
|
||||
sub-second convergence. This may involve diverting the routes from one
|
||||
nexthop to another.
|
||||
|
||||
Overview of changes
|
||||
------------------------
|
||||
|
||||
The changes are in both BGP and Zebra modules. The short summary is
|
||||
the following:
|
||||
|
||||
- Zebra implements a registration mechanism by which clients can
|
||||
register for next hop notification. Consequently, it maintains a
|
||||
separate table, per (VRF, AF) pair, of next hops and interested
|
||||
client-list per next hop.
|
||||
|
||||
- When the main routing table changes in Zebra, it evaluates the next
|
||||
hop table: for each next hop, it checks if the route table
|
||||
modifications have changed its state. If so, it notifies the
|
||||
interested clients.
|
||||
|
||||
- BGP is one such client. It registers the next hops corresponding to
|
||||
all of its received routes/paths. It also threads the paths against
|
||||
each nexthop structure.
|
||||
|
||||
- When BGP receives a next hop notification from Zebra, it walks the
|
||||
corresponding path list. It makes them valid or invalid depending
|
||||
on the next hop notification. It then re-computes best path for the
|
||||
corresponding destination. This may result in re-announcing those
|
||||
destinations to peers.
|
||||
|
||||
Design
|
||||
------
|
||||
|
||||
Modules
|
||||
~~~~~~~
|
||||
|
||||
The core design introduces an "nht" (next hop tracking) module in BGP
|
||||
and "rnh" (recursive nexthop) module in Zebra. The "nht" module
|
||||
provides the following APIs:
|
||||
|
||||
+----------------------------+--------------------------------------------------+
|
||||
| Function | Action |
|
||||
+============================+==================================================+
|
||||
| bgp_find_or_add_nexthop() | find or add a nexthop in BGP nexthop table |
|
||||
+----------------------------+--------------------------------------------------+
|
||||
| bgp_find_nexthop() | find a nexthop in BGP nexthop table |
|
||||
+----------------------------+--------------------------------------------------+
|
||||
| bgp_parse_nexthop_update() | parse a nexthop update message coming from zebra |
|
||||
+----------------------------+--------------------------------------------------+
|
||||
|
||||
The "rnh" module provides the following APIs:
|
||||
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| Function | Action |
|
||||
+============================+==========================================================================================================+
|
||||
| zebra_add_rnh() | add a recursive nexthop |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| zebra_delete_rnh() | delete a recursive nexthop |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| zebra_lookup_rnh() | lookup a recursive nexthop |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| zebra_add_rnh_client() | register a client for nexthop notifications against a recursive nexthop |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| zebra_remove_rnh_client() | remove the client registration for a recursive nexthop |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| zebra_evaluate_rnh_table() | (re)evaluate the recursive nexthop table (most probably because the main routing table has changed). |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| zebra_cleanup_rnh_client() | Cleanup a client from the "rnh" module data structures (most probably because the client is going away). |
|
||||
+----------------------------+----------------------------------------------------------------------------------------------------------+
|
||||
|
||||
4.2. Control flow
|
||||
|
||||
The next hop registration control flow is the following:
|
||||
|
||||
::
|
||||
|
||||
<==== BGP Process ====>|<==== Zebra Process ====>
|
||||
|
|
||||
receive module nht module | zserv module rnh module
|
||||
----------------------------------------------------------------------
|
||||
| | |
|
||||
bgp_update_ | | |
|
||||
main() | bgp_find_or_add_ | |
|
||||
| nexthop() | |
|
||||
| | |
|
||||
| | zserv_nexthop_ |
|
||||
| | register() |
|
||||
| | | zebra_add_rnh()
|
||||
| | |
|
||||
|
||||
|
||||
The next hop notification control flow is the following:
|
||||
|
||||
::
|
||||
|
||||
<==== Zebra Process ====>|<==== BGP Process ====>
|
||||
|
|
||||
rib module rnh module | zebra module nht module
|
||||
----------------------------------------------------------------------
|
||||
| | |
|
||||
meta_queue_ | | |
|
||||
process() | zebra_evaluate_ | |
|
||||
| rnh_table() | |
|
||||
| | |
|
||||
| | bgp_read_nexthop_ |
|
||||
| | update() |
|
||||
| | | bgp_parse_
|
||||
| | | nexthop_update()
|
||||
| | |
|
||||
|
||||
|
||||
zclient message format
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are
|
||||
encoded in the following way:
|
||||
|
||||
::
|
||||
|
||||
. 0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| AF | prefix len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. Nexthop prefix .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| AF | prefix len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. Nexthop prefix .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
``ZEBRA_NEXTHOP_UPDATE`` message is encoded as follows:
|
||||
|
||||
::
|
||||
|
||||
. 0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| AF | prefix len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. Nexthop prefix getting resolved .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| metric |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| #nexthops |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| nexthop type |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. resolving Nexthop details .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| nexthop type |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
. resolving Nexthop details .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
BGP data structure
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Legend:
|
||||
|
||||
::
|
||||
|
||||
/\ struct bgp_node: a BGP destination/route/prefix
|
||||
\/
|
||||
|
||||
[ ] struct bgp_info: a BGP path (e.g. route received from a peer)
|
||||
|
||||
_
|
||||
(_) struct bgp_nexthop_cache: a BGP nexthop
|
||||
|
||||
/\ NULL
|
||||
\/--+ ^
|
||||
| :
|
||||
+--[ ]--[ ]--[ ]--> NULL
|
||||
/\ :
|
||||
\/--+ :
|
||||
| :
|
||||
+--[ ]--[ ]--> NULL
|
||||
:
|
||||
_ :
|
||||
(_)...........
|
||||
|
||||
|
||||
Zebra data structure
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
RNH table::
|
||||
|
||||
O
|
||||
/ \
|
||||
O O
|
||||
/ \
|
||||
O O
|
||||
|
||||
struct rnh
|
||||
{
|
||||
u_char flags;
|
||||
struct route_entry *state;
|
||||
struct list *client_list;
|
||||
struct route_node *node;
|
||||
};
|
||||
|
||||
User interface changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
frr# show ip nht
|
||||
3.3.3.3
|
||||
resolved via kernel
|
||||
via 11.0.0.6, swp1
|
||||
Client list: bgp(fd 12)
|
||||
11.0.0.10
|
||||
resolved via connected
|
||||
is directly connected, swp2
|
||||
Client list: bgp(fd 12)
|
||||
11.0.0.18
|
||||
resolved via connected
|
||||
is directly connected, swp4
|
||||
Client list: bgp(fd 12)
|
||||
11.11.11.11
|
||||
resolved via kernel
|
||||
via 10.0.1.2, eth0
|
||||
Client list: bgp(fd 12)
|
||||
|
||||
frr# show ip bgp nexthop
|
||||
Current BGP nexthop cache:
|
||||
3.3.3.3 valid [IGP metric 0], #paths 3
|
||||
Last update: Wed Oct 16 04:43:49 2013
|
||||
|
||||
11.0.0.10 valid [IGP metric 1], #paths 1
|
||||
Last update: Wed Oct 16 04:43:51 2013
|
||||
|
||||
11.0.0.18 valid [IGP metric 1], #paths 2
|
||||
Last update: Wed Oct 16 04:43:47 2013
|
||||
|
||||
11.11.11.11 valid [IGP metric 0], #paths 1
|
||||
Last update: Wed Oct 16 04:43:47 2013
|
||||
|
||||
frr# show ipv6 nht
|
||||
frr# show ip bgp nexthop detail
|
||||
|
||||
frr# debug bgp nht
|
||||
frr# debug zebra nht
|
||||
|
||||
6. Sample test cases
|
||||
|
||||
r2----r3
|
||||
/ \ /
|
||||
r1----r4
|
||||
|
||||
- Verify that a change in IGP cost triggers NHT
|
||||
+ shutdown the r1-r4 and r2-r4 links
|
||||
+ no shut the r1-r4 and r2-r4 links and wait for OSPF to come back
|
||||
up
|
||||
+ We should be back to the original nexthop via r4 now
|
||||
- Verify that a NH becoming unreachable triggers NHT
|
||||
+ Shutdown all links to r4
|
||||
- Verify that a NH becoming reachable triggers NHT
|
||||
+ no shut all links to r4
|
||||
|
||||
Future work
|
||||
~~~~~~~~~~~
|
||||
|
||||
- route-policy for next hop validation (e.g. ignore default route)
|
||||
- damping for rapid next hop changes
|
||||
- prioritized handling of nexthop changes ((un)reachability vs. metric
|
||||
changes)
|
||||
- handling recursion loop, e.g::
|
||||
|
||||
11.11.11.11/32 -> 12.12.12.12
|
||||
12.12.12.12/32 -> 11.11.11.11
|
||||
11.0.0.0/8 -> <interface>
|
||||
- better statistics
|
388
doc/developer/ospf-api.rst
Normal file
@ -0,0 +1,388 @@
|
||||
OSPF API Documentation
|
||||
======================
|
||||
|
||||
Disclaimer
|
||||
----------
|
||||
|
||||
The OSPF daemon contains an API for application access to the LSA
|
||||
database. This API was created by Ralph Keller, originally as patch for
|
||||
Zebra. Unfortunately, the page containing documentation of the API is no
|
||||
longer online. This page is an attempt to recreate documentation for the
|
||||
API (with lots of help of the WayBackMachine)
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This page describes an API that allows external applications to access
|
||||
the link-state database (LSDB) of the OSPF daemon. The implementation is
|
||||
based on the OSPF code from FRRouting (forked from Quagga and formerly
|
||||
Zebra) routing protocol suite and is subject to the GNU General Public
|
||||
License. The OSPF API provides you with the following functionality:
|
||||
|
||||
- Retrieval of the full or partial link-state database of the OSPF
|
||||
daemon. This allows applications to obtain an exact copy of the LSDB
|
||||
including router LSAs, network LSAs and so on. Whenever a new LSA
|
||||
arrives at the OSPF daemon, the API module immediately informs the
|
||||
application by sending a message. This way, the application is always
|
||||
synchronized with the LSDB of the OSPF daemon.
|
||||
- Origination of own opaque LSAs (of type 9, 10, or 11) which are then
|
||||
distributed transparently to other routers within the flooding scope
|
||||
and received by other applications through the OSPF API.
|
||||
|
||||
Opaque LSAs, which are described in RFC 2370 , allow you to distribute
|
||||
application-specific information within a network using the OSPF
|
||||
protocol. The information contained in opaque LSAs is transparent for
|
||||
the routing process but it can be processed by other modules such as
|
||||
traffic engineering (e.g., MPLS-TE).
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
The following picture depicts the architecture of the Quagga/Zebra
|
||||
protocol suite. The OSPF daemon is extended with opaque LSA capabilities
|
||||
and an API for external applications. The OSPF core module executes the
|
||||
OSPF protocol by discovering neighbors and exchanging neighbor state.
|
||||
The opaque module, implemented by Masahiko Endo, provides functions to
|
||||
exchange opaque LSAs between routers. Opaque LSAs can be generated by
|
||||
several modules such as the MPLS-TE module or the API server module.
|
||||
These modules then invoke the opaque module to flood their data to
|
||||
neighbors within the flooding scope.
|
||||
|
||||
The client, which is an application potentially running on a different
|
||||
node than the OSPF daemon, links against the OSPF API client library.
|
||||
This client library establishes a socket connection with the API server
|
||||
module of the OSPF daemon and uses this connection to retrieve LSAs and
|
||||
originate opaque LSAs.
|
||||
|
||||
.. figure:: ../figures/ospf_api_architecture.png
|
||||
:alt: image
|
||||
|
||||
image
|
||||
|
||||
The OSPF API server module works like any other internal opaque module
|
||||
(such as the MPLS-TE module), but listens to connections from external
|
||||
applications that want to communicate with the OSPF daemon. The API
|
||||
server module can handle multiple clients concurrently.
|
||||
|
||||
One of the main objectives of the implementation is to make as little
|
||||
changes to the existing Zebra code as possible.
|
||||
|
||||
Installation & Configuration
|
||||
----------------------------
|
||||
|
||||
Download FRRouting and unpack
|
||||
|
||||
Configure your frr version (note that --enable-opaque-lsa also enables
|
||||
the ospfapi server and ospfclient).
|
||||
|
||||
::
|
||||
|
||||
% update-autotools
|
||||
% sh ./configure --enable-opaque-lsa
|
||||
% make
|
||||
|
||||
This should also compile the client library and sample application in
|
||||
ospfclient.
|
||||
|
||||
Make sure that you have enabled opaque LSAs in your configuration. Add
|
||||
the ospf opaque-lsa statement to your ospfd.conf:
|
||||
|
||||
::
|
||||
|
||||
! -*- ospf -*-
|
||||
!
|
||||
! OSPFd sample configuration file
|
||||
!
|
||||
!
|
||||
hostname xxxxx
|
||||
password xxxxx
|
||||
|
||||
router ospf
|
||||
router-id 10.0.0.1
|
||||
network 10.0.0.1/24 area 1
|
||||
neighbor 10.0.0.2
|
||||
network 10.0.1.2/24 area 1
|
||||
neighbor 10.0.1.1
|
||||
ospf opaque-lsa <============ add this statement!
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
In the following we describe how you can use the sample application to
|
||||
originate opaque LSAs. The sample application first registers with the
|
||||
OSPF daemon the opaque type it wants to inject and then waits until the
|
||||
OSPF daemon is ready to accept opaque LSAs of that type. Then the client
|
||||
application originates an opaque LSA, waits 10 seconds and then updates
|
||||
the opaque LSA with new opaque data. After another 20 seconds, the
|
||||
client application deletes the opaque LSA from the LSDB. If the clients
|
||||
terminates unexpectedly, the OSPF API module will remove all the opaque
|
||||
LSAs that the application registered. Since the opaque LSAs are flooded
|
||||
to other routers, we will see the opaque LSAs in all routers according
|
||||
to the flooding scope of the opaque LSA.
|
||||
|
||||
We have a very simple demo setup, just two routers connected with an ATM
|
||||
point-to-point link. Start the modified OSPF daemons on two adjacent
|
||||
routers. First run on msr2:
|
||||
|
||||
::
|
||||
|
||||
> msr2:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf
|
||||
|
||||
And on the neighboring router msr3:
|
||||
|
||||
::
|
||||
|
||||
> msr3:/home/keller/ospfapi/zebra/ospfd# ./ospfd -f /usr/local/etc/ospfd.conf
|
||||
|
||||
Now the two routers form adjacency and start exchanging their databases.
|
||||
Looking at the OSPF daemon of msr2 (or msr3), you see this:
|
||||
|
||||
::
|
||||
|
||||
ospfd> show ip ospf database
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
Router Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum Link count
|
||||
10.0.0.1 10.0.0.1 55 0x80000003 0xc62f 2
|
||||
10.0.0.2 10.0.0.2 55 0x80000003 0xe3e4 3
|
||||
|
||||
Net Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum
|
||||
10.0.0.2 10.0.0.2 60 0x80000001 0x5fcb
|
||||
|
||||
Now we start the sample main application that originates an opaque LSA.
|
||||
|
||||
::
|
||||
|
||||
> cd ospfapi/apiclient
|
||||
> ./main msr2 10 250 20 0.0.0.0 0.0.0.1
|
||||
|
||||
This originates an opaque LSA of type 10 (area local), with opaque type
|
||||
250 (experimental), opaque id of 20 (chosen arbitrarily), interface
|
||||
address 0.0.0.0 (which is used only for opaque LSAs type 9), and area
|
||||
0.0.0.1
|
||||
|
||||
Again looking at the OSPF database you see:
|
||||
|
||||
::
|
||||
|
||||
ospfd> show ip ospf database
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
Router Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum Link count
|
||||
10.0.0.1 10.0.0.1 437 0x80000003 0xc62f 2
|
||||
10.0.0.2 10.0.0.2 437 0x80000003 0xe3e4 3
|
||||
|
||||
Net Link States (Area 0.0.0.1)
|
||||
|
||||
Link ID ADV Router Age Seq# CkSum
|
||||
10.0.0.2 10.0.0.2 442 0x80000001 0x5fcb
|
||||
|
||||
Area-Local Opaque-LSA (Area 0.0.0.1)
|
||||
|
||||
Opaque-Type/Id ADV Router Age Seq# CkSum
|
||||
250.0.0.20 10.0.0.1 0 0x80000001 0x58a6 <=== opaque LSA
|
||||
|
||||
You can take a closer look at this opaque LSA:
|
||||
|
||||
::
|
||||
|
||||
ospfd> show ip ospf database opaque-area
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
|
||||
Area-Local Opaque-LSA (Area 0.0.0.1)
|
||||
|
||||
LS age: 4
|
||||
Options: 66
|
||||
LS Type: Area-Local Opaque-LSA
|
||||
Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
|
||||
Advertising Router: 10.0.0.1
|
||||
LS Seq Number: 80000001
|
||||
Checksum: 0x58a6
|
||||
Length: 24
|
||||
Opaque-Type 250 (Private/Experimental)
|
||||
Opaque-ID 0x14
|
||||
Opaque-Info: 4 octets of data
|
||||
Added using OSPF API: 4 octets of opaque data
|
||||
Opaque data: 1 0 0 0 <==== counter is 1
|
||||
|
||||
Note that the main application updates the opaque LSA after 10 seconds,
|
||||
then it looks as follows:
|
||||
|
||||
::
|
||||
|
||||
ospfd> show ip ospf database opaque-area
|
||||
|
||||
OSPF Router with ID (10.0.0.1)
|
||||
|
||||
|
||||
Area-Local Opaque-LSA (Area 0.0.0.1)
|
||||
|
||||
LS age: 1
|
||||
Options: 66
|
||||
LS Type: Area-Local Opaque-LSA
|
||||
Link State ID: 250.0.0.20 (Area-Local Opaque-Type/ID)
|
||||
Advertising Router: 10.0.0.1
|
||||
LS Seq Number: 80000002
|
||||
Checksum: 0x59a3
|
||||
Length: 24
|
||||
Opaque-Type 250 (Private/Experimental)
|
||||
Opaque-ID 0x14
|
||||
Opaque-Info: 4 octets of data
|
||||
Added using OSPF API: 4 octets of opaque data
|
||||
Opaque data: 2 0 0 0 <==== counter is now 2
|
||||
|
||||
Note that the payload of the opaque LSA has changed as you can see
|
||||
above.
|
||||
|
||||
Then, again after another 20 seconds, the opaque LSA is flushed from the
|
||||
LSDB.
|
||||
|
||||
Important note:
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
In order to originate an opaque LSA, there must be at least one active
|
||||
opaque-capable neighbor. Thus, you cannot originate opaque LSAs of no
|
||||
neighbors are present. If you try to originate even so no neighbor is
|
||||
ready, you will receive a not ready error message. The reason for this
|
||||
restriction is that it might be possible that some routers have an
|
||||
identical opaque LSA from a previous origination in their LSDB that
|
||||
unfortunately could not be flushed due to a crash, and now if the router
|
||||
comes up again and starts originating a new opaque LSA, the new opaque
|
||||
LSA is considered older since it has a lower sequence number and is
|
||||
ignored by other routers (that consider the stalled opaque LSA as more
|
||||
recent). However, if the originating router first synchronizes the
|
||||
database before originating opaque LSAs, it will detect the older opaque
|
||||
LSA and can flush it first.
|
||||
|
||||
Protocol and Message Formats
|
||||
----------------------------
|
||||
|
||||
If you are developing your own client application and you don't want to
|
||||
make use of the client library (due to the GNU license restriction or
|
||||
whatever reason), you can implement your own client-side message
|
||||
handling. The OSPF API uses two connections between the client and the
|
||||
OSPF API server: One connection is used for a synchronous request /reply
|
||||
protocol and another connection is used for asynchronous notifications
|
||||
(e.g., LSA update, neighbor status change).
|
||||
|
||||
Each message begins with the following header:
|
||||
|
||||
.. figure:: ../figures/ospf_api_msghdr.png
|
||||
:alt: image
|
||||
|
||||
image
|
||||
|
||||
The message type field can take one of the following values:
|
||||
|
||||
+-------------------------------+---------+
|
||||
| Messages to OSPF deamon | Value |
|
||||
+===============================+=========+
|
||||
| MSG\_REGISTER\_OPAQUETYPE | 1 |
|
||||
+-------------------------------+---------+
|
||||
| MSG\_UNREGISTER\_OPAQUETYPE | 2 |
|
||||
+-------------------------------+---------+
|
||||
| MSG\_REGISTER\_EVENT | 3 |
|
||||
+-------------------------------+---------+
|
||||
| MSG\_SYNC\_LSDB | 4 |
|
||||
+-------------------------------+---------+
|
||||
| MSG\_ORIGINATE\_REQUEST | 5 |
|
||||
+-------------------------------+---------+
|
||||
| MSG\_DELETE\_REQUEST | 6 |
|
||||
+-------------------------------+---------+
|
||||
|
||||
+-----------------------------+---------+
|
||||
| Messages from OSPF deamon | Value |
|
||||
+=============================+=========+
|
||||
| MSG\_REPLY | 10 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_READY\_NOTIFY | 11 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_LSA\_UPDATE\_NOTIFY | 12 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_LSA\_DELETE\_NOTIFY | 13 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_NEW\_IF | 14 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_DEL\_IF | 15 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_ISM\_CHANGE | 16 |
|
||||
+-----------------------------+---------+
|
||||
| MSG\_NSM\_CHANGE | 17 |
|
||||
+-----------------------------+---------+
|
||||
|
||||
The synchronous requests and replies have the following message formats:
|
||||
|
||||
.. figure:: ../figures/ospf_api_msgs1.png
|
||||
:alt: image
|
||||
|
||||
image
|
||||
|
||||
The origin field allows to select according to the following types of
|
||||
origins:
|
||||
|
||||
+-------------------------+---------+
|
||||
| Origin | Value |
|
||||
+=========================+=========+
|
||||
| NON\_SELF\_ORIGINATED | 0 |
|
||||
+-------------------------+---------+
|
||||
| SELF\_ORIGINATED | 1 |
|
||||
+-------------------------+---------+
|
||||
| ANY\_ORIGIN | 2 |
|
||||
+-------------------------+---------+
|
||||
|
||||
The reply message has on of the following error codes:
|
||||
|
||||
+--------------------------+---------+
|
||||
| Error code | Value |
|
||||
+==========================+=========+
|
||||
| API\_OK | 0 |
|
||||
+--------------------------+---------+
|
||||
| API\_NOSUCHINTERFACE | -1 |
|
||||
+--------------------------+---------+
|
||||
| API\_NOSUCHAREA | -2 |
|
||||
+--------------------------+---------+
|
||||
| API\_NOSUCHLSA | -3 |
|
||||
+--------------------------+---------+
|
||||
| API\_ILLEGALSATYPE | -4 |
|
||||
+--------------------------+---------+
|
||||
| API\_ILLEGALOPAQUETYPE | -5 |
|
||||
+--------------------------+---------+
|
||||
| API\_OPAQUETYPEINUSE | -6 |
|
||||
+--------------------------+---------+
|
||||
| API\_NOMEMORY | -7 |
|
||||
+--------------------------+---------+
|
||||
| API\_ERROR | -99 |
|
||||
+--------------------------+---------+
|
||||
| API\_UNDEF | -100 |
|
||||
+--------------------------+---------+
|
||||
|
||||
The asynchronous notifications have the following message formats:
|
||||
|
||||
.. figure:: ../figures/ospf_api_msgs2.png
|
||||
:alt: image
|
||||
|
||||
image
|
||||
|
||||
Original Acknowledgments from Ralph Keller
|
||||
------------------------------------------
|
||||
|
||||
I would like to thank Masahiko Endo, the author of the opaque LSA
|
||||
extension module, for his great support. His wonderful ASCII graphs
|
||||
explaining the internal workings of this code, and his invaluable input
|
||||
proved to be crucial in designing a useful API for accessing the link
|
||||
state database of the OSPF daemon. Once, he even decided to take the
|
||||
plane from Tokyo to Zurich so that we could actually meet and have
|
||||
face-to-face discussions, which was a lot of fun. Clearly, without
|
||||
Masahiko no API would ever be completed. I also would like to thank
|
||||
Daniel Bauer who wrote an opaque LSA implementation too and was willing
|
||||
to test the OSPF API code in one of his projects.
|
@ -21,9 +21,9 @@ Supported Features
|
||||
Interoperability
|
||||
----------------
|
||||
|
||||
* tested on various topology including point-to-point and LAN interfaces
|
||||
* Tested on various topology including point-to-point and LAN interfaces
|
||||
in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x
|
||||
* check OSPF LSA conformity with latest wireshark release 2.5.0-rc
|
||||
* Check OSPF LSA conformity with latest wireshark release 2.5.0-rc
|
||||
|
||||
Implementation details
|
||||
----------------------
|
||||
@ -196,17 +196,17 @@ yourself:
|
||||
|
||||
::
|
||||
|
||||
modprobe mpls_router
|
||||
modprobe mpls_gso
|
||||
modprobe mpls_iptunnel
|
||||
modprobe mpls_router
|
||||
modprobe mpls_gso
|
||||
modprobe mpls_iptunnel
|
||||
|
||||
Then, you must activate MPLS on the interface you would used:
|
||||
|
||||
::
|
||||
|
||||
sysctl -w net.mpls.conf.enp0s9.input=1
|
||||
sysctl -w net.mpls.conf.lo.input=1
|
||||
sysctl -w net.mpls.platform_labels=1048575
|
||||
sysctl -w net.mpls.conf.enp0s9.input=1
|
||||
sysctl -w net.mpls.conf.lo.input=1
|
||||
sysctl -w net.mpls.platform_labels=1048575
|
||||
|
||||
The last line fix the maximum MPLS label value.
|
||||
|
||||
@ -215,8 +215,8 @@ enable with:
|
||||
|
||||
::
|
||||
|
||||
ip -M route
|
||||
ip route
|
||||
ip -M route
|
||||
ip route
|
||||
|
||||
The first command show the MPLS LFIB table while the second show the FIB
|
||||
table which contains route with MPLS label encapsulation.
|
||||
@ -227,8 +227,8 @@ especially the `lo` one. For that purpose, disable RP filtering with:
|
||||
|
||||
::
|
||||
|
||||
systcl -w net.ipv4.conf.all.rp_filter=0
|
||||
sysctl -w net.ipv4.conf.lo.rp_filter=0
|
||||
systcl -w net.ipv4.conf.all.rp_filter=0
|
||||
sysctl -w net.ipv4.conf.lo.rp_filter=0
|
||||
|
||||
OSPFd
|
||||
~~~~~
|
||||
@ -240,16 +240,16 @@ Routing.
|
||||
|
||||
::
|
||||
|
||||
router ospf
|
||||
ospf router-id 192.168.1.11
|
||||
capability opaque
|
||||
mpls-te on
|
||||
mpls-te router-address 192.168.1.11
|
||||
router-info area 0.0.0.0
|
||||
segment-routing on
|
||||
segment-routing global-block 10000 19999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 192.168.1.11/32 index 1100
|
||||
router ospf
|
||||
ospf router-id 192.168.1.11
|
||||
capability opaque
|
||||
mpls-te on
|
||||
mpls-te router-address 192.168.1.11
|
||||
router-info area 0.0.0.0
|
||||
segment-routing on
|
||||
segment-routing global-block 10000 19999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 192.168.1.11/32 index 1100
|
||||
|
||||
The first segment-routing statement enable it. The Second one set the SRGB,
|
||||
third line the MSD and finally, set the Prefix SID index for a given prefix.
|
||||
@ -283,4 +283,3 @@ This work has been performed in the framework of the H2020-ICT-2014
|
||||
project 5GEx (Grant Agreement no. 671636), which is partially funded
|
||||
by the European Commission.
|
||||
|
||||
|
657
doc/developer/workflow.rst
Normal file
@ -0,0 +1,657 @@
|
||||
.. _process-and-workflow:
|
||||
|
||||
*******************
|
||||
Process & Workflow
|
||||
*******************
|
||||
|
||||
FRR is a large project developed by many different groups. This section
|
||||
documents standards for code style & quality, commit messages, pull requests
|
||||
and best practices that all contributors are asked to follow.
|
||||
|
||||
This chapter is "descriptive/post-factual" in that it documents pratices that
|
||||
are in use; it is not "definitive/pre-factual" in prescribing practices. This
|
||||
means that when a procedure changes, it is agreed upon, then put into practice,
|
||||
and then documented here. If this document doesn't match reality, it's the
|
||||
document that needs to be updated, not reality.
|
||||
|
||||
Mailing Lists
|
||||
=============
|
||||
|
||||
The FRR development group maintains multiple mailing lists for use by the
|
||||
community. Italicized lists are private.
|
||||
|
||||
+----------------------------------+--------------------------------+
|
||||
| Topic | List |
|
||||
+==================================+================================+
|
||||
| Development | dev@lists.frrouting.org |
|
||||
+----------------------------------+--------------------------------+
|
||||
| Users & Operators | frog@lists.frrouting.org |
|
||||
+----------------------------------+--------------------------------+
|
||||
| Announcements | announce@lists.frrouting.org |
|
||||
+----------------------------------+--------------------------------+
|
||||
| *Security* | security@lists.frrouting.org |
|
||||
+----------------------------------+--------------------------------+
|
||||
| *Technical Steering Committee* | tsc@lists.frrouting.org |
|
||||
+----------------------------------+--------------------------------+
|
||||
|
||||
The Development list is used to discuss and document general issues related to
|
||||
project development and governance. The public Slack instance,
|
||||
frrouting.slack.com, and weekly technical meetings provide a higher bandwidth
|
||||
channel for discussions. The results of such discussions must be reflected in
|
||||
updates, as appropriate, to code (i.e., merges), `Github issues`_, and for
|
||||
governance or process changes, updates to the Development list and either this
|
||||
file or information posted at https://frrouting.org/.
|
||||
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
The changelog will be the base for the release notes. A changelog entry for
|
||||
your changes is usually not required and will be added based on your commit
|
||||
messages by the maintainers. However, you are free to include an update to the
|
||||
changelog with some better description.
|
||||
|
||||
Submitting Patches and Enhancements
|
||||
===================================
|
||||
|
||||
FRR accepts patches from two sources:
|
||||
|
||||
- Email (git format-patch)
|
||||
- Github pull request
|
||||
|
||||
Contributors are highly encouraged to use Github's fork-and-pr workflow. It is
|
||||
easier for us to review it, test it, try it and discuss it on Github than it is
|
||||
via email, thus your patch will get more attention more quickly on Github.
|
||||
|
||||
The base branch for new contributions and non-critical bug fixes should be
|
||||
``master``. Please ensure your pull request is based on this branch when you
|
||||
submit it.
|
||||
|
||||
Pre-submission Checklist
|
||||
------------------------
|
||||
|
||||
- Format code (see `Code Formatting <#developers-guidelines>`__)
|
||||
- Verify and acknowledge license (see `License for
|
||||
contributions <#license-for-contributions>`__)
|
||||
- Ensure you have properly signed off (see `Signing
|
||||
Off <#signing-off>`__)
|
||||
- Test building with various configurations:
|
||||
|
||||
- ``buildtest.sh``
|
||||
|
||||
- Verify building source distribution:
|
||||
|
||||
- ``make dist`` (and try rebuilding from the resulting tar file)
|
||||
|
||||
- Run unit tests:
|
||||
|
||||
- ``make test``
|
||||
|
||||
- Document Regression Runs and plans for continued maintenance of the
|
||||
feature
|
||||
|
||||
License for contributions
|
||||
-------------------------
|
||||
|
||||
FRR is under a “GPLv2 or later” license. Any code submitted must
|
||||
be released under the same license (preferred) or any license which
|
||||
allows redistribution under this GPLv2 license (eg MIT License).
|
||||
|
||||
Signing Off
|
||||
-----------
|
||||
|
||||
Code submitted to FRR must be signed off. We have the same
|
||||
requirements for using the signed-off-by process as the Linux kernel. In
|
||||
short, you must include a signed-off-by tag in every patch.
|
||||
|
||||
``Signed-off-by:`` this is a developer's certification that he or she
|
||||
has the right to submit the patch for inclusion into the project. It is
|
||||
an agreement to the Developer's Certificate of Origin (below). Code
|
||||
without a proper signoff can not and will not be merged.
|
||||
|
||||
If you are unfamiliar with this process, you should read the `official
|
||||
policy at
|
||||
kernel.org <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>`__
|
||||
and you might find this article about `participating in the Linux
|
||||
community on the Linux Foundation
|
||||
website <http://www.linuxfoundation.org/content/how-participate-linux-community-0>`__
|
||||
to be a helpful resource.
|
||||
|
||||
In short, when you sign off on a commit, you assert your agreement to
|
||||
all of the following:
|
||||
|
||||
::
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part by
|
||||
me, under the same open source license (unless I am permitted to
|
||||
submit under a different license), as indicated in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
|
||||
What do I submit my changes against?
|
||||
------------------------------------
|
||||
|
||||
We've documented where we would like to have the different fixes applied
|
||||
at
|
||||
https://github.com/FRR/frr/wiki/Where-Do-I-create-a-Pull-Request-against%3F
|
||||
If you are unsure where your submission goes, look at that document or
|
||||
ask a project maintainer.
|
||||
|
||||
Github pull requests
|
||||
--------------------
|
||||
|
||||
The preferred method of submitting changes is a Github pull request.
|
||||
Code submitted by pull request will be automatically tested by one or
|
||||
more CI systems. Once the automated tests succeed, other developers will
|
||||
review your code for quality and correctness. After any concerns are
|
||||
resolved, your code will be merged into the branch it was submitted
|
||||
against.
|
||||
|
||||
Patch submission via mailing list
|
||||
---------------------------------
|
||||
|
||||
As an alternative submission method, a patch can be mailed to the
|
||||
development mailing list. Patches received on the mailing list will be
|
||||
picked up by Patchwork and tested against the latest development branch.
|
||||
|
||||
The recommended way to send the patch (or series of NN patches) to the
|
||||
list is by using ``git send-email`` as follows (assuming they are the N
|
||||
most recent commit(s) in your git history:
|
||||
|
||||
::
|
||||
|
||||
git send-email -NN --annotate --to=dev@lists.frrouting.org
|
||||
|
||||
If your commits do not already contain a ``Signed-off-by`` line, then
|
||||
use the following command to add it (after making sure you agree to the
|
||||
Developer Certificate of Origin as outlined above):
|
||||
|
||||
::
|
||||
|
||||
git send-email -NN --annotate --signoff --to=dev@lists.frrouting.org
|
||||
|
||||
Submitting multi-commit patches as a Github pull request is **strongly
|
||||
encouraged** and increases the probability of your patch getting
|
||||
reviewed and merged in a timely manner.
|
||||
|
||||
After submitting your changes
|
||||
-----------------------------
|
||||
|
||||
- Watch for Continuous Integration (CI) Test results
|
||||
|
||||
- You should automatically receive an email with the test results
|
||||
within less than 2 hrs of the submission. If you don’t get the
|
||||
email, then check status on the Github pull request.
|
||||
- Please notify the development mailing list if you think something
|
||||
doesn't work.
|
||||
|
||||
- If the tests failed:
|
||||
|
||||
- In general, expect the community to ignore the submission until
|
||||
the tests pass.
|
||||
- It is up to you to fix and resubmit.
|
||||
|
||||
- This includes fixing existing unit (“make test”) tests if your
|
||||
changes broke or changed them.
|
||||
- It also includes fixing distribution packages for the failing
|
||||
platforms (ie if new libraries are required).
|
||||
- Feel free to ask for help on the development list.
|
||||
|
||||
- Go back to the submission process and repeat until the tests pass.
|
||||
|
||||
- If the tests pass:
|
||||
|
||||
- Wait for reviewers. Someone will review your code or be assigned
|
||||
to review your code.
|
||||
- Respond to any comments or concerns the reviewer has.
|
||||
- After all comments and concerns are addressed, expect your patch
|
||||
to be merged.
|
||||
|
||||
- Watch out for questions on the mailing list. At this time there will
|
||||
be a manual code review and further (longer) tests by various
|
||||
community members.
|
||||
- Your submission is done once it is merged to the master branch.
|
||||
|
||||
Git Structure
|
||||
=============
|
||||
|
||||
.. figure:: ../figures/git_branches.png
|
||||
:align: center
|
||||
:scale: 55%
|
||||
:alt: Merging Git branches into a central trunk
|
||||
|
||||
Rough outline of FRR development workflow
|
||||
|
||||
The master Git for FRR resides on `GitHub`_.
|
||||
|
||||
There is one main branch for development, ``master``. For each major release
|
||||
(2.0, 3.0 etc) a new release branch is created based on the master. Subsequent
|
||||
point releases based on a major branch are marked by tagging.
|
||||
|
||||
Programming Languages, Tools and Libraries
|
||||
==========================================
|
||||
|
||||
The core of FRR is written in C (gcc or clang supported) and makes
|
||||
use of GNU compiler extensions. A few non-essential scripts are
|
||||
implemented in Perl and Python. FRR requires the following tools
|
||||
to build distribution packages: automake, autoconf, texinfo, libtool and
|
||||
gawk and various libraries (i.e. libpam and libjson-c).
|
||||
|
||||
If your contribution requires a new library or other tool, then please
|
||||
highlight this in your description of the change. Also make sure it’s
|
||||
supported by all FRR platform OSes or provide a way to build
|
||||
without the library (potentially without the new feature) on the other
|
||||
platforms.
|
||||
|
||||
Documentation should be written in reStructuredText. Sphinx extensions may be
|
||||
utilized but pure ReST is preferred where possible. See
|
||||
:ref:`documentation`.
|
||||
|
||||
|
||||
Coding Practices & Style
|
||||
========================
|
||||
|
||||
Commit messages
|
||||
---------------
|
||||
|
||||
Commit messages should be formatted in the same way as Linux kernel
|
||||
commit messages. The format is roughly
|
||||
|
||||
::
|
||||
|
||||
dir: short summary
|
||||
|
||||
extended summary
|
||||
|
||||
``dir`` should be the top level source directory under which the change
|
||||
was made. For example, a change in bgpd/rfapi would be formatted as:::
|
||||
|
||||
bgpd: short summary
|
||||
|
||||
The first line should be no longer than 50 characters. Subsequent lines
|
||||
should be wrapped to 72 characters.
|
||||
|
||||
Source file header
|
||||
------------------
|
||||
|
||||
New files need to have a Copyright header (see `License for
|
||||
contributions <#license-for-contributions>`__ above) added to the file.
|
||||
Preferred form of the header is as follows:
|
||||
|
||||
::
|
||||
|
||||
/*
|
||||
* Title/Function of file
|
||||
* Copyright (C) YEAR Author’s Name
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
Adding copyright claims to existing files
|
||||
-----------------------------------------
|
||||
|
||||
When adding copyright claims for modifications to an existing file,
|
||||
please preface the claim with "Portions: " on a line before it and
|
||||
indent the "Copyright ..." string. If such a case already exists, add
|
||||
your indented claim immediately after. E.g.:
|
||||
|
||||
::
|
||||
|
||||
Portions:
|
||||
Copyright (C) 2010 Entity A ....
|
||||
Copyright (C) 2016 Your name [optional brief change description]
|
||||
|
||||
Code formatting
|
||||
---------------
|
||||
|
||||
FRR uses Linux kernel style except where noted below. Code which does
|
||||
not comply with these style guidelines will not be accepted.
|
||||
|
||||
To assist with compliance, in the project root there is a .clang-format
|
||||
configuration file which can be used with the ``clang-format`` tool from
|
||||
the LLVM project. In the ``tools/`` directory there is a Python script
|
||||
named ``indent.py`` that wraps clang-format and handles some edge cases
|
||||
specific to FRR. If you are submitting a new file, it is recommended to
|
||||
run that script over the new file after ensuring that the latest stable
|
||||
release of ``clang-format`` is in your PATH.
|
||||
|
||||
**Whitespace changes in untouched parts of the code are not acceptable
|
||||
in patches that change actual code.** To change/fix formatting issues,
|
||||
please create a separate patch that only does formatting changes and
|
||||
nothing else.
|
||||
|
||||
Kernel and BSD styles are documented externally:
|
||||
|
||||
- https://www.kernel.org/doc/html/latest/process/coding-style.html
|
||||
- http://man.openbsd.org/style
|
||||
|
||||
For GNU coding style, use ``indent`` with the following invocation:
|
||||
|
||||
::
|
||||
|
||||
indent -nut -nfc1 file_for_submission.c
|
||||
|
||||
Exceptions
|
||||
^^^^^^^^^^
|
||||
|
||||
FRR project code comes from a variety of sources, so there are some
|
||||
stylistic exceptions in place. They are organized here by branch.
|
||||
|
||||
For ``master``
|
||||
""""""""""""""
|
||||
|
||||
BSD coding style applies to:
|
||||
|
||||
- ``ldpd/``
|
||||
|
||||
``babeld`` uses, approximately, the following style:
|
||||
|
||||
- K&R style braces
|
||||
- Indents are 4 spaces
|
||||
- Function return types are on their own line
|
||||
|
||||
For ``stable/3.0`` and ``stable/2.0``
|
||||
"""""""""""""""""""""""""""""""""""""
|
||||
|
||||
GNU coding style apply to the following parts:
|
||||
|
||||
- ``lib/``
|
||||
- ``zebra/``
|
||||
- ``bgpd/``
|
||||
- ``ospfd/``
|
||||
- ``ospf6d/``
|
||||
- ``isisd/``
|
||||
- ``ripd/``
|
||||
- ``ripngd/``
|
||||
- ``vtysh/``
|
||||
|
||||
BSD coding style applies to:
|
||||
|
||||
- ``ldpd/``
|
||||
|
||||
Compile-time conditional code
|
||||
-----------------------------
|
||||
|
||||
Many users access FRR via binary packages from 3rd party sources;
|
||||
compile-time code puts inclusion/exclusion in the hands of the package
|
||||
maintainer. Please think very carefully before making code conditional
|
||||
at compile time, as it increases regression testing, maintenance
|
||||
burdens, and user confusion. In particular, please avoid gratuitous
|
||||
``--enable-…`` switches to the configure script - in general, code
|
||||
should be of high quality and in working condition, or it shouldn’t be
|
||||
in FRR at all.
|
||||
|
||||
When code must be compile-time conditional, try have the compiler make
|
||||
it conditional rather than the C pre-processor so that it will still be
|
||||
checked by the compiler, even if disabled. For example,
|
||||
|
||||
::
|
||||
|
||||
if (SOME_SYMBOL)
|
||||
frobnicate();
|
||||
|
||||
is preferred to
|
||||
|
||||
::
|
||||
|
||||
#ifdef SOME_SYMBOL
|
||||
frobnicate ();
|
||||
#endif /* SOME_SYMBOL */
|
||||
|
||||
Note that the former approach requires ensuring that ``SOME_SYMBOL``
|
||||
will be defined (watch your ``AC_DEFINE``\ s).
|
||||
|
||||
Debug-guards in code
|
||||
--------------------
|
||||
|
||||
Debugging statements are an important methodology to allow developers to
|
||||
fix issues found in the code after it has been released. The caveat here
|
||||
is that the developer must remember that people will be using the code
|
||||
at scale and in ways that can be unexpected for the original
|
||||
implementor. As such debugs **MUST** be guarded in such a way that they
|
||||
can be turned off. FRR has the ability to turn on/off debugs from the
|
||||
CLI and it is expected that the developer will use this convention to
|
||||
allow control of their debugs.
|
||||
|
||||
CLI changes
|
||||
-----------
|
||||
|
||||
CLI's are a complicated ugly beast. Additions or changes to the CLI
|
||||
should use a DEFUN to encapsulate one setting as much as is possible.
|
||||
Additionally as new DEFUN's are added to the system, documentation
|
||||
should be provided for the new commands.
|
||||
|
||||
Backwards Compatibility
|
||||
-----------------------
|
||||
|
||||
As a general principle, changes to CLI and code in the lib/ directory
|
||||
should be made in a backwards compatible fashion. This means that
|
||||
changes that are purely stylistic in nature should be avoided, e.g.,
|
||||
renaming an existing macro or library function name without any
|
||||
functional change. When adding new parameters to common functions, it is
|
||||
also good to consider if this too should be done in a backward
|
||||
compatible fashion, e.g., by preserving the old form in addition to
|
||||
adding the new form.
|
||||
|
||||
This is not to say that minor or even major functional changes to CLI
|
||||
and common code should be avoided, but rather that the benefit gained
|
||||
from a change should be weighed against the added cost/complexity to
|
||||
existing code. Also, that when making such changes, it is good to
|
||||
preserve compatibility when possible to do so without introducing
|
||||
maintenance overhead/cost. It is also important to keep in mind,
|
||||
existing code includes code that may reside in private repositories (and
|
||||
is yet to be submitted) or code that has yet to be migrated from Quagga
|
||||
to FRR.
|
||||
|
||||
That said, compatibility measures can (and should) be removed when
|
||||
either:
|
||||
|
||||
- they become a significant burden, e.g. when data structures change
|
||||
and the compatibility measure would need a complex adaptation layer
|
||||
or becomes flat-out impossible
|
||||
- some measure of time (dependent on the specific case) has passed, so
|
||||
that the compatibility grace period is considered expired.
|
||||
|
||||
In all cases, compatibility pieces should be marked with
|
||||
compiler/preprocessor annotations to print warnings at compile time,
|
||||
pointing to the appropriate update path. A ``-Werror`` build should fail
|
||||
if compatibility bits are used.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
When in doubt, follow the guidelines in the Linux kernel style guide, or
|
||||
ask on the development mailing list / public Slack instance.
|
||||
|
||||
|
||||
.. _documentation:
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
FRR uses Sphinx+RST as its documentation system. The document you are currently
|
||||
reading was generated by Sphinx from RST source in
|
||||
:file:`doc/developer/workflow.rst`. The documentation is structured as follows:
|
||||
|
||||
+-----------------------+--------------------------------------------------------------+
|
||||
| Directory | Contents |
|
||||
+=======================+==============================================================+
|
||||
| :file:`doc/user` | User documentation; configuration guides; protocol overviews |
|
||||
+-----------------------+--------------------------------------------------------------+
|
||||
| :file:`doc/developer` | Developer's documentation; API specs; datastructures; |
|
||||
| | architecture overviews; project management procedure |
|
||||
+-----------------------+--------------------------------------------------------------+
|
||||
| :file:`doc/manpages` | Source for manpages |
|
||||
+-----------------------+--------------------------------------------------------------+
|
||||
| :file:`doc/figures` | Images and diagrams |
|
||||
+-----------------------+--------------------------------------------------------------+
|
||||
|
||||
Each of these directories, with the exception of :file:`doc/figures`, contains
|
||||
a Sphinx-generated Makefile and configuration script :file:`conf.py` used to
|
||||
set various document parameters. The makefile can be used for a variety of
|
||||
targets; invoke `make help` in any of these directories for a listing of
|
||||
available output formats. For convenience, there is a top-level
|
||||
:file:`Makefile.am` that has targets for PDF and HTML documentation for both
|
||||
developer and user documentation, respectively. That makefile is also
|
||||
responsible for building manual pages packed with distribution builds.
|
||||
|
||||
Indent and styling should follow existing conventions:
|
||||
|
||||
- 3 spaces for indents under directives
|
||||
- Cross references may contain only lowercase alphanumeric characters and
|
||||
hyphens ('-')
|
||||
- Lines wrapped to 80 characters where possible
|
||||
|
||||
Characters for header levels should follow Python documentation guide:
|
||||
|
||||
- ``#`` with overline, for parts
|
||||
- ``*`` with overline, for chapters
|
||||
- ``=``, for sections
|
||||
- ``-``, for subsections
|
||||
- ``^``, for subsubsections
|
||||
- ``"``, for paragraphs
|
||||
|
||||
After you have made your changes, please make sure that you can invoke
|
||||
``make latexpdf`` and ``make html`` with no warnings.
|
||||
|
||||
The documentation is currently incomplete and needs love. If you find a broken
|
||||
cross-reference, figure, dead hyperlink, style issue or any other nastiness we
|
||||
gladly accept documentation patches.
|
||||
|
||||
To build the docs, please ensure you have installed a recent version of
|
||||
`Sphinx <http://www.sphinx-doc.org/en/stable/install.html>`_. If you want to
|
||||
build LaTeX or PDF docs, you will also need a full LaTeX distribution
|
||||
installed.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
FRR is a large and complex software project developed by many different people
|
||||
over a long period of time. Without adequate documentation, it can be
|
||||
exceedingly difficult to understand code segments, APIs and other interfaces.
|
||||
In the interest of keeping the project healthy and maintainable, you should
|
||||
make every effort to document your code so that other people can understand
|
||||
what it does without needing to closely read the code itself.
|
||||
|
||||
Some specific guidelines that contributors should follow are:
|
||||
|
||||
- Functions exposed in header files should have descriptive comments above
|
||||
their signatures in the header file. At a minimum, a function comment should
|
||||
contain information about the return value, parameters, and a general summary
|
||||
of the function's purpose. Documentation on parameter values can be omitted
|
||||
if it is (very) obvious what they are used for.
|
||||
|
||||
Function comments must follow the style for multiline comments laid out in
|
||||
the kernel style guide.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/*
|
||||
* Determines whether or not a string is cool.
|
||||
*
|
||||
* @param text - the string to check for coolness
|
||||
* @param is_clccfc - whether capslock is cruise control for cool
|
||||
* @return 7 if the text is cool, 0 otherwise
|
||||
*/
|
||||
int check_coolness(const char *text, bool is_clccfc);
|
||||
|
||||
The Javadoc-style annotations are not required, but you should still strive
|
||||
to make it equally clear what parameters and return values are used for.
|
||||
|
||||
- Static functions should have descriptive comments in the same form as above
|
||||
if what they do is not immediately obvious. Use good engineering judgement
|
||||
when deciding whether a comment is necessary. If you are unsure, document
|
||||
your code.
|
||||
- Global variables, static or not, should have a comment describing their use.
|
||||
- **For new code in lib/, these guidelines are hard requirements.**
|
||||
|
||||
If you make significant changes to portions of the codebase covered in the
|
||||
Developer's Manual, add a major subsystem or feature, or gain arcane mastery of
|
||||
some undocumented or poorly documented part of the codebase, please document
|
||||
your work so others can benefit. If you add a major feature or introduce a new
|
||||
API, please document the architecture and API to the best of your abilities in
|
||||
the Developer's Manual, using good judgement when choosing where to place it.
|
||||
|
||||
Finally, if you come across some code that is undocumented and feel like
|
||||
going above and beyond, document it! We absolutely appreciate and accept
|
||||
patches that document previously undocumented code.
|
||||
|
||||
User
|
||||
----
|
||||
|
||||
If you are contributing code that adds significant user-visible functionality
|
||||
please document how to use it in :file:`doc/user`. Use good judgement when
|
||||
choosing where to place documentation. For example, instructions on how to use
|
||||
your implementation of a new BGP draft should go in the BGP chapter instead of
|
||||
being its own chapter. If you are adding a new protocol daemon, please create a
|
||||
new chapter.
|
||||
|
||||
When documenting CLI please use a combination of the ``.. index::`` and
|
||||
``.. clicmd::`` directives. For example, the command :clicmd:`show pony` would
|
||||
be documented as follows:
|
||||
|
||||
.. code-block:: rest
|
||||
|
||||
.. index:: show pony
|
||||
.. clicmd:: show pony
|
||||
|
||||
Prints an ASCII pony. Example output:::
|
||||
|
||||
>>\.
|
||||
/_ )`.
|
||||
/ _)`^)`. _.---. _
|
||||
(_,' \ `^-)"" `.\
|
||||
| | \
|
||||
\ / |
|
||||
/ \ /.___.'\ (\ (_
|
||||
< ,"|| \ |`. \`-'
|
||||
\\ () )| )/
|
||||
hjw |_>|> /_] //
|
||||
/_] /_]
|
||||
|
||||
When documented this way, CLI commands can be cross referenced with the
|
||||
``:clicmd:`` inline markup like so:
|
||||
|
||||
.. code-block:: rest
|
||||
|
||||
:clicmd:`show pony`
|
||||
|
||||
This is very helpful for users who want to quickly remind themselves what a
|
||||
particular command does.
|
||||
|
||||
.. _GitHub: https://github.com/frrouting/frr
|
||||
.. _GitHub issues: https://github.com/frrouting/frr/issues
|
122
doc/eigrpd.8.in
@ -1,122 +0,0 @@
|
||||
.TH EIGRPD 8 "6 May 2017" "@PACKAGE_FULLNAME@ EIGRP daemon" "Version @PACKAGE_VERSION@"
|
||||
.SH NAME
|
||||
eigrpd \- a EIGRP routing engine for use with @PACKAGE_FULLNAME@.
|
||||
.SH SYNOPSIS
|
||||
.B eigrpd
|
||||
[
|
||||
.B \-dhrv
|
||||
] [
|
||||
.B \-f
|
||||
.I config-file
|
||||
] [
|
||||
.B \-i
|
||||
.I pid-file
|
||||
] [
|
||||
.B \-P
|
||||
.I port-number
|
||||
] [
|
||||
.B \-A
|
||||
.I vty-address
|
||||
] [
|
||||
.B \-u
|
||||
.I user
|
||||
] [
|
||||
.B \-g
|
||||
.I group
|
||||
] [
|
||||
.B \-M
|
||||
.I module:options
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B eigrpd
|
||||
is a routing component that works with the
|
||||
.B @PACKAGE_FULLNAME@
|
||||
routing engine.
|
||||
.SH OPTIONS
|
||||
Options available for the
|
||||
.B eigrpd
|
||||
command:
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-daemon\fR
|
||||
Runs in daemon mode, forking and exiting from tty.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
|
||||
Specifies the config file to use for startup. If not specified this
|
||||
option will default to \fB\fI@CFG_SYSCONF@/eigrpd.conf\fR.
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR
|
||||
Specify the group to run as. Default is \fI@enable_group@\fR.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
A brief message.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
|
||||
When eigrpd starts its process identifier is written to
|
||||
\fB\fIpid-file\fR. The init system uses the recorded PID to stop or
|
||||
restart eigrpd. The default is \fB\fI@CFG_STATE@/eigrpd.pid\fR.
|
||||
.TP
|
||||
\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR
|
||||
Specify the port that the eigrpd VTY will listen on. This defaults to
|
||||
2602, as specified in \fB\fI/etc/services\fR.
|
||||
.TP
|
||||
\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR
|
||||
Specify the address that the eigrpd VTY will listen on. Default is all
|
||||
interfaces.
|
||||
.TP
|
||||
\fB\-u\fR, \fB\-\-user \fR\fIuser\fR
|
||||
Specify the user to run as. Default is \fI@enable_user@\fR.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-retain\fR
|
||||
When the program terminates, retain routes added by \fBeigrpd\fR.
|
||||
.TP
|
||||
\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR
|
||||
Load a module at startup. May be specified more than once.
|
||||
The \fBsnmp\fR module may be available for
|
||||
\fBeigrpd\fR, if the package was built with SNMP support.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Print the version and exit.
|
||||
.SH FILES
|
||||
.TP
|
||||
.BI @CFG_SBIN@/eigrpd
|
||||
The default location of the
|
||||
.B eigrpd
|
||||
binary.
|
||||
.TP
|
||||
.BI @CFG_SYSCONF@/eigrpd.conf
|
||||
The default location of the
|
||||
.B eigrpd
|
||||
config file.
|
||||
.TP
|
||||
.BI $(PWD)/eigrpd.log
|
||||
If the
|
||||
.B eigrpd
|
||||
process is config'd to output logs to a file, then you will find this
|
||||
file in the directory where you started \fBeigrpd\fR.
|
||||
.SH WARNING
|
||||
This man page is intended to be a quick reference for command line
|
||||
options. The definitive document is the Info file \fB@PACKAGE_NAME@\fR.
|
||||
.SH DIAGNOSTICS
|
||||
The eigrpd process may log to standard output, to a VTY, to a log
|
||||
file, or through syslog to the system logs. \fBeigrpd\fR supports many
|
||||
debugging options, see the Info file, or the source for details.
|
||||
.SH "SEE ALSO"
|
||||
.BR bgpd (8),
|
||||
.BR ripd (8),
|
||||
.BR ripngd (8),
|
||||
.BR ospfd (8),
|
||||
.BR ospf6d (8),
|
||||
.BR isisd (8),
|
||||
.BR zebra (8),
|
||||
.BR vtysh (1)
|
||||
.SH BUGS
|
||||
.B eigrpd
|
||||
eats bugs for breakfast. If you have food for the maintainers try
|
||||
.BI @PACKAGE_BUGREPORT@
|
||||
.SH AUTHORS
|
||||
See
|
||||
.BI http://www.zebra.org
|
||||
and
|
||||
.BI @PACKAGE_URL@
|
||||
or the Info file for an accurate list of authors.
|
216
doc/eigrpd.texi
@ -1,216 +0,0 @@
|
||||
@c -*-texinfo-*-
|
||||
@c This is part of the Frr Manual.
|
||||
@c @value{COPYRIGHT_STR}
|
||||
@c See file frr.texi for copying conditions.
|
||||
@node EIGRP
|
||||
@chapter EIGRP
|
||||
|
||||
EIGRP -- Routing Information Protocol is widely deployed interior gateway
|
||||
routing protocol. EIGRP was developed in the 1990's. EIGRP is a
|
||||
@dfn{distance-vector} protocol and is based on the @dfn{dual} algorithms.
|
||||
As a distance-vector protocol, the EIGRP router send updates to its
|
||||
neighbors as networks change, thus allowing the convergence to a
|
||||
known topology.
|
||||
|
||||
@command{eigrpd} supports EIGRP as described in RFC7868
|
||||
|
||||
@menu
|
||||
* Starting and Stopping eigrpd::
|
||||
* EIGRP Configuration::
|
||||
* How to Announce EIGRP routes::
|
||||
* Show EIGRP Information::
|
||||
* EIGRP Debug Commands::
|
||||
@end menu
|
||||
|
||||
@node Starting and Stopping eigrpd
|
||||
@section Starting and Stopping eigrpd
|
||||
|
||||
The default configuration file name of @command{eigrpd}'s is
|
||||
@file{eigrpd.conf}. When invocation @command{eigrpd} searches directory
|
||||
@value{INSTALL_PREFIX_ETC}. If @file{eigrpd.conf} is not there next
|
||||
search current directory. If an integrated config is specified
|
||||
configuration is written into frr.conf
|
||||
|
||||
The EIGRP protocol requires interface information
|
||||
maintained by @command{zebra} daemon. So running @command{zebra}
|
||||
is mandatory to run @command{eigrpd}. Thus minimum sequence for running
|
||||
EIGRP is like below:
|
||||
|
||||
@example
|
||||
@group
|
||||
# zebra -d
|
||||
# eigrpd -d
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Please note that @command{zebra} must be invoked before @command{eigrpd}.
|
||||
|
||||
To stop @command{eigrpd}. Please use @command{kill `cat
|
||||
/var/run/eigrpd.pid`}. Certain signals have special meanings to @command{eigrpd}.
|
||||
|
||||
@table @samp
|
||||
@item SIGHUP
|
||||
@item SIGUSR1
|
||||
Rotate @command{eigrpd} Rotate the logfile.
|
||||
@item SIGINT
|
||||
@itemx SIGTERM
|
||||
@command{eigrpd} sweeps all installed EIGRP routes then terminates properly.
|
||||
@end table
|
||||
|
||||
@command{eigrpd} invocation options. Common options that can be specified
|
||||
(@pxref{Common Invocation Options}).
|
||||
|
||||
@table @samp
|
||||
@item -r
|
||||
@itemx --retain
|
||||
When the program terminates, retain routes added by @command{eigrpd}.
|
||||
@end table
|
||||
|
||||
@node EIGRP Configuration
|
||||
@section EIGRP Configuration
|
||||
|
||||
@deffn Command {router eigrp (1-65535)} {}
|
||||
The @code{router eigrp} command is necessary to enable EIGRP. To disable
|
||||
EIGRP, use the @code{no router eigrp (1-65535)} command. EIGRP must be enabled before carrying out any of the EIGRP commands.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {no router eigrp (1-65535)} {}
|
||||
Disable EIGRP.
|
||||
@end deffn
|
||||
|
||||
@deffn {EIGRP Command} {network @var{network}} {}
|
||||
@deffnx {EIGRP Command} {no network @var{network}} {}
|
||||
Set the EIGRP enable interface by @var{network}. The interfaces which
|
||||
have addresses matching with @var{network} are enabled.
|
||||
|
||||
This group of commands either enables or disables EIGRP interfaces between
|
||||
certain numbers of a specified network address. For example, if the
|
||||
network for 10.0.0.0/24 is EIGRP enabled, this would result in all the
|
||||
addresses from 10.0.0.0 to 10.0.0.255 being enabled for EIGRP. The @code{no
|
||||
network} command will disable EIGRP for the specified network.
|
||||
@end deffn
|
||||
|
||||
Below is very simple EIGRP configuration. Interface @code{eth0} and
|
||||
interface which address match to @code{10.0.0.0/8} are EIGRP enabled.
|
||||
|
||||
@example
|
||||
@group
|
||||
!
|
||||
router eigrp 1
|
||||
network 10.0.0.0/8
|
||||
!
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Passive interface
|
||||
|
||||
@deffn {EIGRP command} {passive-interface (@var{IFNAME}|default)} {}
|
||||
@deffnx {EIGRP command} {no passive-interface @var{IFNAME}} {}
|
||||
This command sets the specified interface to passive mode. On passive mode
|
||||
interface, all receiving packets are ignored and eigrpd does
|
||||
not send either multicast or unicast EIGRP packets except to EIGRP neighbors
|
||||
specified with @code{neighbor} command. The interface may be specified
|
||||
as @var{default} to make eigrpd default to passive on all interfaces.
|
||||
|
||||
The default is to be passive on all interfaces.
|
||||
@end deffn
|
||||
|
||||
@node How to Announce EIGRP route
|
||||
@section How to Announce EIGRP route
|
||||
|
||||
@deffn {EIGRP command} {redistribute kernel} {}
|
||||
@deffnx {EIGRP command} {redistribute kernel metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
|
||||
@deffnx {EIGRP command} {no redistribute kernel} {}
|
||||
@code{redistribute kernel} redistributes routing information from
|
||||
kernel route entries into the EIGRP tables. @code{no redistribute kernel}
|
||||
disables the routes.
|
||||
@end deffn
|
||||
|
||||
@deffn {EIGRP command} {redistribute static} {}
|
||||
@deffnx {EIGRP command} {redistribute static metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
|
||||
@deffnx {EIGRP command} {no redistribute static} {}
|
||||
@code{redistribute static} redistributes routing information from
|
||||
static route entries into the EIGRP tables. @code{no redistribute static}
|
||||
disables the routes.
|
||||
@end deffn
|
||||
|
||||
@deffn {EIGRP command} {redistribute connected} {}
|
||||
@deffnx {EIGRP command} {redistribute connected metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
|
||||
@deffnx {EIGRP command} {no redistribute connected} {}
|
||||
Redistribute connected routes into the EIGRP tables. @code{no
|
||||
redistribute connected} disables the connected routes in the EIGRP tables.
|
||||
This command redistribute connected of the interface which EIGRP disabled.
|
||||
The connected route on EIGRP enabled interface is announced by default.
|
||||
@end deffn
|
||||
|
||||
@deffn {EIGRP command} {redistribute ospf} {}
|
||||
@deffnx {EIGRP command} {redistribute ospf metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
|
||||
@deffnx {EIGRP command} {no redistribute ospf} {}
|
||||
@code{redistribute ospf} redistributes routing information from
|
||||
ospf route entries into the EIGRP tables. @code{no redistribute ospf}
|
||||
disables the routes.
|
||||
@end deffn
|
||||
|
||||
@deffn {EIGRP command} {redistribute bgp} {}
|
||||
@deffnx {EIGRP command} {redistribute bgp metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
|
||||
@deffnx {EIGRP command} {no redistribute bgp} {}
|
||||
@code{redistribute bgp} redistributes routing information from
|
||||
bgp route entries into the EIGRP tables. @code{no redistribute bgp}
|
||||
disables the routes.
|
||||
@end deffn
|
||||
|
||||
@node Show EIGRP Information
|
||||
@section Show EIGRP Information
|
||||
|
||||
To display EIGRP routes.
|
||||
|
||||
@deffn Command {show ip eigrp topology} {}
|
||||
Show EIGRP routes.
|
||||
@end deffn
|
||||
|
||||
The command displays all EIGRP routes.
|
||||
|
||||
@c Exmaple here.
|
||||
|
||||
@deffn Command {show ip eigrp topology} {}
|
||||
The command displays current EIGRP status
|
||||
@end deffn
|
||||
|
||||
@example
|
||||
@group
|
||||
eigrpd> @b{show ip eigrp topology}
|
||||
# show ip eigrp topo
|
||||
|
||||
EIGRP Topology Table for AS(4)/ID(0.0.0.0)
|
||||
|
||||
Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply
|
||||
r - reply Status, s - sia Status
|
||||
|
||||
P 10.0.2.0/24, 1 successors, FD is 256256, serno: 0
|
||||
via Connected, enp0s3
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@node EIGRP Debug Commands
|
||||
@section EIGRP Debug Commands
|
||||
|
||||
Debug for EIGRP protocol.
|
||||
|
||||
@deffn Command {debug eigrp packets} {}
|
||||
Debug eigrp packets
|
||||
@end deffn
|
||||
|
||||
@code{debug eigrp} will show EIGRP packets that are sent and recevied.
|
||||
|
||||
@deffn Command {debug eigrp transmit} {}
|
||||
Debug eigrp transmit events
|
||||
@end deffn
|
||||
|
||||
@code{debug eigrp transmit} will display detailed information about the EIGRP transmit events.
|
||||
|
||||
@deffn Command {show debugging eigrp} {}
|
||||
Display @command{eigrpd}'s debugging option.
|
||||
@end deffn
|
||||
|
||||
@code{show debugging eigrp} will show all information currently set for eigrpd
|
||||
debug.
|
211
doc/figures/cligraph.svg
Normal file
@ -0,0 +1,211 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
||||
-->
|
||||
<!-- Title: %3 Pages: 1 -->
|
||||
<svg width="300pt" height="980pt"
|
||||
viewBox="0.00 0.00 299.50 980.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 976)">
|
||||
<title>%3</title>
|
||||
<polygon fill="white" stroke="none" points="-4,4 -4,-976 295.5,-976 295.5,4 -4,4"/>
|
||||
<!-- n0xd46960 -->
|
||||
<g id="node1" class="node"><title>n0xd46960</title>
|
||||
<polygon fill="#ccffcc" stroke="black" points="158,-972 86,-972 86,-936 158,-936 158,-972"/>
|
||||
<text text-anchor="start" x="94" y="-952.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">START_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd46be0 -->
|
||||
<g id="node2" class="node"><title>n0xd46be0</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="159,-900 85,-900 85,-864 159,-864 159,-900"/>
|
||||
<text text-anchor="start" x="93" y="-885.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">WORD_TKN</text>
|
||||
<text text-anchor="start" x="101.5" y="-875.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
<text text-anchor="start" x="105.5" y="-875.2" font-family="Fira Mono" font-weight="bold" font-size="11.00" fill="#0055ff">show</text>
|
||||
<text text-anchor="start" x="138.5" y="-875.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
</g>
|
||||
<!-- n0xd46960->n0xd46be0 -->
|
||||
<g id="edge1" class="edge"><title>n0xd46960->n0xd46be0</title>
|
||||
<path fill="none" stroke="black" d="M122,-935.697C122,-927.983 122,-918.712 122,-910.112"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-910.104 122,-900.104 118.5,-910.104 125.5,-910.104"/>
|
||||
</g>
|
||||
<!-- n0xd47f80 -->
|
||||
<g id="node3" class="node"><title>n0xd47f80</title>
|
||||
<polygon fill="#aaddff" stroke="black" points="156.5,-828 87.5,-828 87.5,-792 156.5,-792 156.5,-828"/>
|
||||
<text text-anchor="start" x="95.5" y="-808.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">FORK_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd46be0->n0xd47f80 -->
|
||||
<g id="edge2" class="edge"><title>n0xd46be0->n0xd47f80</title>
|
||||
<path fill="none" stroke="black" d="M122,-863.697C122,-855.983 122,-846.712 122,-838.112"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-838.104 122,-828.104 118.5,-838.104 125.5,-838.104"/>
|
||||
</g>
|
||||
<!-- n0xd47c70 -->
|
||||
<g id="node4" class="node"><title>n0xd47c70</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="127,-756 53,-756 53,-720 127,-720 127,-756"/>
|
||||
<text text-anchor="start" x="61" y="-741.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">WORD_TKN</text>
|
||||
<text text-anchor="start" x="80.5" y="-731.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
<text text-anchor="start" x="84.5" y="-731.2" font-family="Fira Mono" font-weight="bold" font-size="11.00" fill="#0055ff">ip</text>
|
||||
<text text-anchor="start" x="95.5" y="-731.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
</g>
|
||||
<!-- n0xd47f80->n0xd47c70 -->
|
||||
<g id="edge3" class="edge"><title>n0xd47f80->n0xd47c70</title>
|
||||
<path fill="none" stroke="black" d="M114.09,-791.697C110.447,-783.728 106.046,-774.1 102.006,-765.264"/>
|
||||
<polygon fill="black" stroke="black" points="105.16,-763.744 97.8191,-756.104 98.7936,-766.654 105.16,-763.744"/>
|
||||
</g>
|
||||
<!-- n0xd484c0 -->
|
||||
<g id="node5" class="node"><title>n0xd484c0</title>
|
||||
<polygon fill="#ddaaff" stroke="black" points="153.5,-684 90.5,-684 90.5,-648 153.5,-648 153.5,-684"/>
|
||||
<text text-anchor="start" x="98.5" y="-664.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">JOIN_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd47f80->n0xd484c0 -->
|
||||
<g id="edge20" class="edge"><title>n0xd47f80->n0xd484c0</title>
|
||||
<path fill="none" stroke="black" d="M127.824,-791.56C130.931,-781.33 134.431,-768.08 136,-756 138.06,-740.133 138.06,-735.867 136,-720 134.897,-711.506 132.839,-702.434 130.634,-694.24"/>
|
||||
<polygon fill="black" stroke="black" points="133.945,-693.087 127.824,-684.44 127.216,-695.017 133.945,-693.087"/>
|
||||
</g>
|
||||
<!-- n0xd47c70->n0xd484c0 -->
|
||||
<g id="edge4" class="edge"><title>n0xd47c70->n0xd484c0</title>
|
||||
<path fill="none" stroke="black" d="M97.9101,-719.697C101.553,-711.728 105.954,-702.1 109.994,-693.264"/>
|
||||
<polygon fill="black" stroke="black" points="113.206,-694.654 114.181,-684.104 106.84,-691.744 113.206,-694.654"/>
|
||||
</g>
|
||||
<!-- n0xd47ca0 -->
|
||||
<g id="node6" class="node"><title>n0xd47ca0</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="159,-612 85,-612 85,-576 159,-576 159,-612"/>
|
||||
<text text-anchor="start" x="93" y="-597.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">WORD_TKN</text>
|
||||
<text text-anchor="start" x="106.5" y="-587.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
<text text-anchor="start" x="110.5" y="-587.2" font-family="Fira Mono" font-weight="bold" font-size="11.00" fill="#0055ff">bgp</text>
|
||||
<text text-anchor="start" x="133.5" y="-587.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
</g>
|
||||
<!-- n0xd484c0->n0xd47ca0 -->
|
||||
<g id="edge5" class="edge"><title>n0xd484c0->n0xd47ca0</title>
|
||||
<path fill="none" stroke="black" d="M122,-647.697C122,-639.983 122,-630.712 122,-622.112"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-622.104 122,-612.104 118.5,-622.104 125.5,-622.104"/>
|
||||
</g>
|
||||
<!-- n0xd48540 -->
|
||||
<g id="node7" class="node"><title>n0xd48540</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="164.5,-540 79.5,-540 79.5,-504 164.5,-504 164.5,-540"/>
|
||||
<text text-anchor="start" x="93" y="-525.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">WORD_TKN</text>
|
||||
<text text-anchor="start" x="87.5" y="-515.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
<text text-anchor="start" x="91.5" y="-515.2" font-family="Fira Mono" font-weight="bold" font-size="11.00" fill="#0055ff">neighbors</text>
|
||||
<text text-anchor="start" x="152.5" y="-515.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
</g>
|
||||
<!-- n0xd47ca0->n0xd48540 -->
|
||||
<g id="edge6" class="edge"><title>n0xd47ca0->n0xd48540</title>
|
||||
<path fill="none" stroke="black" d="M122,-575.697C122,-567.983 122,-558.712 122,-550.112"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-550.104 122,-540.104 118.5,-550.104 125.5,-550.104"/>
|
||||
</g>
|
||||
<!-- n0xd490c0 -->
|
||||
<g id="node8" class="node"><title>n0xd490c0</title>
|
||||
<polygon fill="#aaddff" stroke="black" points="156.5,-468 87.5,-468 87.5,-432 156.5,-432 156.5,-468"/>
|
||||
<text text-anchor="start" x="95.5" y="-448.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">FORK_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd48540->n0xd490c0 -->
|
||||
<g id="edge7" class="edge"><title>n0xd48540->n0xd490c0</title>
|
||||
<path fill="none" stroke="black" d="M122,-503.697C122,-495.983 122,-486.712 122,-478.112"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-478.104 122,-468.104 118.5,-478.104 125.5,-478.104"/>
|
||||
</g>
|
||||
<!-- n0xd48fc0 -->
|
||||
<g id="node9" class="node"><title>n0xd48fc0</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="64,-396 0,-396 0,-360 64,-360 64,-396"/>
|
||||
<text text-anchor="start" x="8" y="-380.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">IPV4_TKN</text>
|
||||
<text text-anchor="start" x="15" y="-371.8" font-family="Fira Mono" font-size="9.00">A.B.C.D</text>
|
||||
</g>
|
||||
<!-- n0xd490c0->n0xd48fc0 -->
|
||||
<g id="edge8" class="edge"><title>n0xd490c0->n0xd48fc0</title>
|
||||
<path fill="none" stroke="black" d="M99.7528,-431.697C88.4181,-422.881 74.4698,-412.032 62.1811,-402.474"/>
|
||||
<polygon fill="black" stroke="black" points="64.0336,-399.481 53.9913,-396.104 59.736,-405.007 64.0336,-399.481"/>
|
||||
</g>
|
||||
<!-- n0xd491e0 -->
|
||||
<g id="node10" class="node"><title>n0xd491e0</title>
|
||||
<polygon fill="#ddaaff" stroke="black" points="153.5,-324 90.5,-324 90.5,-288 153.5,-288 153.5,-324"/>
|
||||
<text text-anchor="start" x="98.5" y="-304.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">JOIN_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd490c0->n0xd491e0 -->
|
||||
<g id="edge19" class="edge"><title>n0xd490c0->n0xd491e0</title>
|
||||
<path fill="none" stroke="black" d="M117.536,-431.953C115.065,-421.63 112.248,-408.153 111,-396 109.366,-380.084 109.366,-375.916 111,-360 111.877,-351.455 113.531,-342.255 115.294,-333.958"/>
|
||||
<polygon fill="black" stroke="black" points="118.743,-334.573 117.536,-324.047 111.915,-333.028 118.743,-334.573"/>
|
||||
</g>
|
||||
<!-- n0xd49340 -->
|
||||
<g id="node15" class="node"><title>n0xd49340</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="184,-396 120,-396 120,-360 184,-360 184,-396"/>
|
||||
<text text-anchor="start" x="128" y="-380.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">IPV6_TKN</text>
|
||||
<text text-anchor="start" x="135" y="-371.8" font-family="Fira Mono" font-size="9.00">X:X::X:X</text>
|
||||
</g>
|
||||
<!-- n0xd490c0->n0xd49340 -->
|
||||
<g id="edge15" class="edge"><title>n0xd490c0->n0xd49340</title>
|
||||
<path fill="none" stroke="black" d="M129.416,-431.697C132.794,-423.813 136.87,-414.304 140.623,-405.546"/>
|
||||
<polygon fill="black" stroke="black" points="143.947,-406.675 144.67,-396.104 137.513,-403.917 143.947,-406.675"/>
|
||||
</g>
|
||||
<!-- n0xd49480 -->
|
||||
<g id="node16" class="node"><title>n0xd49480</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="291.5,-396 202.5,-396 202.5,-360 291.5,-360 291.5,-396"/>
|
||||
<text text-anchor="start" x="210.5" y="-380.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">VARIABLE_TKN</text>
|
||||
<text text-anchor="start" x="233" y="-371.8" font-family="Fira Mono" font-size="9.00">WORD</text>
|
||||
</g>
|
||||
<!-- n0xd490c0->n0xd49480 -->
|
||||
<g id="edge17" class="edge"><title>n0xd490c0->n0xd49480</title>
|
||||
<path fill="none" stroke="black" d="M152.578,-431.876C169.074,-422.639 189.624,-411.131 207.336,-401.212"/>
|
||||
<polygon fill="black" stroke="black" points="209.289,-404.13 216.304,-396.19 205.869,-398.022 209.289,-404.13"/>
|
||||
</g>
|
||||
<!-- n0xd48fc0->n0xd491e0 -->
|
||||
<g id="edge9" class="edge"><title>n0xd48fc0->n0xd491e0</title>
|
||||
<path fill="none" stroke="black" d="M54.2472,-359.697C65.5819,-350.881 79.5302,-340.032 91.8189,-330.474"/>
|
||||
<polygon fill="black" stroke="black" points="94.264,-333.007 100.009,-324.104 89.9664,-327.481 94.264,-333.007"/>
|
||||
</g>
|
||||
<!-- n0xd496e0 -->
|
||||
<g id="node11" class="node"><title>n0xd496e0</title>
|
||||
<polygon fill="#aaddff" stroke="black" points="156.5,-252 87.5,-252 87.5,-216 156.5,-216 156.5,-252"/>
|
||||
<text text-anchor="start" x="95.5" y="-232.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">FORK_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd491e0->n0xd496e0 -->
|
||||
<g id="edge10" class="edge"><title>n0xd491e0->n0xd496e0</title>
|
||||
<path fill="none" stroke="black" d="M122,-287.697C122,-279.983 122,-270.712 122,-262.112"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-262.104 122,-252.104 118.5,-262.104 125.5,-262.104"/>
|
||||
</g>
|
||||
<!-- n0xd495e0 -->
|
||||
<g id="node12" class="node"><title>n0xd495e0</title>
|
||||
<polygon fill="#ffffff" stroke="black" points="127,-180 53,-180 53,-144 127,-144 127,-180"/>
|
||||
<text text-anchor="start" x="61" y="-165.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">WORD_TKN</text>
|
||||
<text text-anchor="start" x="73.5" y="-155.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
<text text-anchor="start" x="77.5" y="-155.2" font-family="Fira Mono" font-weight="bold" font-size="11.00" fill="#0055ff">json</text>
|
||||
<text text-anchor="start" x="102.5" y="-155.2" font-family="Fira Mono" font-size="9.00">"</text>
|
||||
</g>
|
||||
<!-- n0xd496e0->n0xd495e0 -->
|
||||
<g id="edge11" class="edge"><title>n0xd496e0->n0xd495e0</title>
|
||||
<path fill="none" stroke="black" d="M114.09,-215.697C110.447,-207.728 106.046,-198.1 102.006,-189.264"/>
|
||||
<polygon fill="black" stroke="black" points="105.16,-187.744 97.8191,-180.104 98.7936,-190.654 105.16,-187.744"/>
|
||||
</g>
|
||||
<!-- n0xd497c0 -->
|
||||
<g id="node13" class="node"><title>n0xd497c0</title>
|
||||
<polygon fill="#ddaaff" stroke="black" points="153.5,-108 90.5,-108 90.5,-72 153.5,-72 153.5,-108"/>
|
||||
<text text-anchor="start" x="98.5" y="-88.8" font-family="Fira Mono" font-weight="bold" font-size="9.00">JOIN_TKN</text>
|
||||
</g>
|
||||
<!-- n0xd496e0->n0xd497c0 -->
|
||||
<g id="edge14" class="edge"><title>n0xd496e0->n0xd497c0</title>
|
||||
<path fill="none" stroke="black" d="M127.824,-215.56C130.931,-205.33 134.431,-192.08 136,-180 138.06,-164.133 138.06,-159.867 136,-144 134.897,-135.506 132.839,-126.434 130.634,-118.24"/>
|
||||
<polygon fill="black" stroke="black" points="133.945,-117.087 127.824,-108.44 127.216,-119.017 133.945,-117.087"/>
|
||||
</g>
|
||||
<!-- n0xd495e0->n0xd497c0 -->
|
||||
<g id="edge12" class="edge"><title>n0xd495e0->n0xd497c0</title>
|
||||
<path fill="none" stroke="black" d="M97.9101,-143.697C101.553,-135.728 105.954,-126.1 109.994,-117.264"/>
|
||||
<polygon fill="black" stroke="black" points="113.206,-118.654 114.181,-108.104 106.84,-115.744 113.206,-118.654"/>
|
||||
</g>
|
||||
<!-- end0xd49900 -->
|
||||
<g id="node14" class="node"><title>end0xd49900</title>
|
||||
<polygon fill="#ffddaa" stroke="black" points="149,-36 95,-36 95,-0 149,-0 149,-36"/>
|
||||
<text text-anchor="start" x="112.5" y="-15.8" font-family="Fira Mono" font-size="9.00">end</text>
|
||||
</g>
|
||||
<!-- n0xd497c0->end0xd49900 -->
|
||||
<g id="edge13" class="edge"><title>n0xd497c0->end0xd49900</title>
|
||||
<path fill="none" stroke="black" d="M122,-71.6966C122,-63.9827 122,-54.7125 122,-46.1124"/>
|
||||
<polygon fill="black" stroke="black" points="125.5,-46.1043 122,-36.1043 118.5,-46.1044 125.5,-46.1043"/>
|
||||
</g>
|
||||
<!-- n0xd49340->n0xd491e0 -->
|
||||
<g id="edge16" class="edge"><title>n0xd49340->n0xd491e0</title>
|
||||
<path fill="none" stroke="black" d="M144.584,-359.697C141.206,-351.813 137.13,-342.304 133.377,-333.546"/>
|
||||
<polygon fill="black" stroke="black" points="136.487,-331.917 129.33,-324.104 130.053,-334.675 136.487,-331.917"/>
|
||||
</g>
|
||||
<!-- n0xd49480->n0xd491e0 -->
|
||||
<g id="edge18" class="edge"><title>n0xd49480->n0xd491e0</title>
|
||||
<path fill="none" stroke="black" d="M216.422,-359.876C199.926,-350.639 179.376,-339.131 161.664,-329.212"/>
|
||||
<polygon fill="black" stroke="black" points="163.131,-326.022 152.696,-324.19 159.711,-332.13 163.131,-326.022"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |