Merge branch 'master' into working/master/bgp-vpn-vrf-leaking
3
.gitignore
vendored
@ -82,3 +82,6 @@ GPATH
|
|||||||
*.lo
|
*.lo
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
.dirstamp
|
.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
|
.arch-ids
|
||||||
*~
|
*~
|
||||||
*.loT
|
*.loT
|
||||||
*clippy.c
|
|
||||||
|
@ -2107,6 +2107,51 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
|
|||||||
return BGP_ATTR_PARSE_PROCEED;
|
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. */
|
/* BGP unknown attribute treatment. */
|
||||||
static bgp_attr_parse_ret_t bgp_attr_unknown(struct bgp_attr_parser_args *args)
|
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:
|
case BGP_ATTR_PREFIX_SID:
|
||||||
ret = bgp_attr_prefix_sid(&attr_args, mp_update);
|
ret = bgp_attr_prefix_sid(&attr_args, mp_update);
|
||||||
break;
|
break;
|
||||||
|
case BGP_ATTR_PMSI_TUNNEL:
|
||||||
|
ret = bgp_attr_pmsi_tunnel(&attr_args);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = bgp_attr_unknown(&attr_args);
|
ret = bgp_attr_unknown(&attr_args);
|
||||||
break;
|
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, BGP_ATTR_PMSI_TUNNEL);
|
||||||
stream_putc(s, 9); // Length
|
stream_putc(s, 9); // Length
|
||||||
stream_putc(s, 0); // Flags
|
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),
|
stream_put(s, &(attr->label),
|
||||||
BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
|
BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
|
||||||
stream_put_ipv4(s, attr->nexthop.s_addr);
|
stream_put_ipv4(s, attr->nexthop.s_addr);
|
||||||
|
@ -66,6 +66,8 @@
|
|||||||
#define BGP_PREFIX_SID_IPV6_LENGTH 19
|
#define BGP_PREFIX_SID_IPV6_LENGTH 19
|
||||||
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
|
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
|
||||||
|
|
||||||
|
/* PMSI tunnel types (RFC 6514) */
|
||||||
|
|
||||||
struct bgp_attr_encap_subtlv {
|
struct bgp_attr_encap_subtlv {
|
||||||
struct bgp_attr_encap_subtlv *next; /* for chaining */
|
struct bgp_attr_encap_subtlv *next; /* for chaining */
|
||||||
/* Reference count of this attribute. */
|
/* Reference count of this attribute. */
|
||||||
@ -96,6 +98,18 @@ struct overlay_index {
|
|||||||
union gw_addr gw_ip;
|
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. */
|
/* BGP core attribute structure. */
|
||||||
struct attr {
|
struct attr {
|
||||||
/* AS Path structure */
|
/* AS Path structure */
|
||||||
@ -119,6 +133,9 @@ struct attr {
|
|||||||
/* Path origin attribute */
|
/* Path origin attribute */
|
||||||
u_char origin;
|
u_char origin;
|
||||||
|
|
||||||
|
/* PMSI tunnel type (RFC 6514). */
|
||||||
|
enum pta_type pmsi_tnl_type;
|
||||||
|
|
||||||
/* has the route-map changed any attribute?
|
/* has the route-map changed any attribute?
|
||||||
Used on the peer outbound side. */
|
Used on the peer outbound side. */
|
||||||
u_int32_t rmap_change_flags;
|
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_str[] = {"i", "e", "?"};
|
||||||
const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"};
|
const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"};
|
||||||
|
|
||||||
|
|
||||||
/* Given a string return a pointer the corresponding peer structure */
|
/* Given a string return a pointer the corresponding peer structure */
|
||||||
static struct peer *bgp_find_peer(struct vty *vty, const char *peer_str)
|
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]));
|
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)))
|
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
|
||||||
snprintf(buf + strlen(buf), size - strlen(buf), ", path %s",
|
snprintf(buf + strlen(buf), size - strlen(buf), ", path %s",
|
||||||
aspath_print(attr->aspath));
|
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)
|
#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
|
||||||
|
|
||||||
extern const char *bgp_type_str[];
|
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_dump_attr(struct attr *, char *, size_t);
|
||||||
extern int bgp_debug_peer_updout_enabled(char *host);
|
extern int bgp_debug_peer_updout_enabled(char *host);
|
||||||
|
204
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);
|
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.
|
* 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
|
* Build extended communities for EVPN route.
|
||||||
* applicable to all routes.
|
* This function is applicable for type-2 and type-3 routes. The layer-2 RT
|
||||||
* TODO: currently kernel doesnt support ipv6 routes with ipv4 nexthops.
|
* and ENCAP extended communities are applicable for all routes.
|
||||||
* This means that we can't do symmetric routing for ipv6 hosts routes
|
* The default gateway extended community and MAC mobility (sticky) extended
|
||||||
* in the same way as ipv4 host routes.
|
* community are added as needed based on passed settings - only for type-2
|
||||||
* We wont attach l3-vni related RTs for ipv6 routes.
|
* routes. Likewise, the layer-3 RT and Router MAC extended communities are
|
||||||
* For now, We will only adevrtise ipv4 host routes
|
* added, if present, based on passed settings - only for non-link-local
|
||||||
* with L3-VNI related ext-comm.
|
* type-2 routes.
|
||||||
*/
|
*/
|
||||||
static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
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_encap;
|
||||||
struct ecommunity ecom_sticky;
|
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))
|
for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
|
||||||
attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
|
attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
|
||||||
|
|
||||||
/*
|
/* Add the export RTs for L3VNI if told to - caller determines
|
||||||
* only attach l3-vni export rts for ipv4 address family and if we are
|
* when this should be done.
|
||||||
* advertising both the labels in type-2 routes
|
|
||||||
*/
|
*/
|
||||||
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);
|
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
|
||||||
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
|
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
|
||||||
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
|
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) {
|
if (attr->sticky) {
|
||||||
seqnum = 0;
|
seqnum = 0;
|
||||||
memset(&ecom_sticky, 0, sizeof(ecom_sticky));
|
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);
|
ecommunity_merge(attr->ecommunity, &ecom_sticky);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Add RMAC, if told to. */
|
||||||
* only attach l3-vni rmac for ipv4 address family and if we are
|
if (add_l3_ecomm) {
|
||||||
* 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)) {
|
|
||||||
memset(&ecom_rmac, 0, sizeof(ecom_rmac));
|
memset(&ecom_rmac, 0, sizeof(ecom_rmac));
|
||||||
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
|
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
|
||||||
ecom_rmac.size = 1;
|
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);
|
ecommunity_merge(attr->ecommunity, &ecom_rmac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add default gateway, if needed. */
|
||||||
if (attr->default_gw) {
|
if (attr->default_gw) {
|
||||||
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
|
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
|
||||||
encode_default_gw_extcomm(&eval_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 bgp_node *rn;
|
||||||
struct attr attr;
|
struct attr attr;
|
||||||
struct attr *attr_new;
|
struct attr *attr_new;
|
||||||
|
int add_l3_ecomm = 0;
|
||||||
struct bgp_info *ri;
|
struct bgp_info *ri;
|
||||||
afi_t afi = AFI_L2VPN;
|
afi_t afi = AFI_L2VPN;
|
||||||
safi_t safi = SAFI_EVPN;
|
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)
|
if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE)
|
||||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
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)
|
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
|
||||||
bgpevpn_get_rmac(vpn, &attr.rmac);
|
bgpevpn_get_rmac(vpn, &attr.rmac);
|
||||||
vni2label(vpn->vni, &(attr.label));
|
vni2label(vpn->vni, &(attr.label));
|
||||||
|
|
||||||
/* Set up RT and ENCAP extended community. */
|
/* Include L3 VNI related RTs and RMAC for type-2 routes, if they're
|
||||||
build_evpn_route_extcomm(
|
* IPv4 or IPv6 global addresses and we're advertising L3VNI with
|
||||||
vpn, &attr, IS_EVPN_PREFIX_IPADDR_V4(p) ? AFI_IP : AFI_IP6);
|
* 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. */
|
/* First, create (or fetch) route node within the VNI. */
|
||||||
/* NOTE: There is no RD here. */
|
/* 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;
|
||||||
struct attr attr_sticky;
|
struct attr attr_sticky;
|
||||||
struct attr attr_def_gw;
|
struct attr attr_def_gw;
|
||||||
struct attr attr_ip6;
|
struct attr attr_ip6_ll;
|
||||||
struct attr attr_sticky_ip6;
|
|
||||||
struct attr attr_def_gw_ip6;
|
|
||||||
struct attr *attr_new;
|
struct attr *attr_new;
|
||||||
|
int add_l3_ecomm = 0;
|
||||||
|
|
||||||
afi = AFI_L2VPN;
|
afi = AFI_L2VPN;
|
||||||
safi = SAFI_EVPN;
|
safi = SAFI_EVPN;
|
||||||
memset(&attr, 0, sizeof(struct attr));
|
memset(&attr, 0, sizeof(struct attr));
|
||||||
memset(&attr_sticky, 0, sizeof(struct attr));
|
memset(&attr_sticky, 0, sizeof(struct attr));
|
||||||
memset(&attr_def_gw, 0, sizeof(struct attr));
|
memset(&attr_def_gw, 0, sizeof(struct attr));
|
||||||
memset(&attr_ip6, 0, sizeof(struct attr));
|
memset(&attr_ip6_ll, 0, sizeof(struct attr));
|
||||||
memset(&attr_sticky_ip6, 0, sizeof(struct attr));
|
|
||||||
memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
|
|
||||||
|
|
||||||
/* Build path-attribute - all type-2 routes for this VNI will share the
|
/* Build path-attribute - multiple type-2 routes for this VNI will share
|
||||||
* same path attribute.
|
* 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, BGP_ORIGIN_IGP);
|
||||||
bgp_attr_default_set(&attr_sticky, 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.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||||
attr_def_gw.default_gw = 1;
|
attr_def_gw.default_gw = 1;
|
||||||
bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
|
bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
|
||||||
bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
|
bgp_attr_default_set(&attr_ip6_ll, BGP_ORIGIN_IGP);
|
||||||
bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
|
attr_ip6_ll.nexthop = vpn->originator_ip;
|
||||||
bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP);
|
attr_ip6_ll.mp_nexthop_global_in = vpn->originator_ip;
|
||||||
attr_ip6.nexthop = vpn->originator_ip;
|
attr_ip6_ll.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||||
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);
|
|
||||||
|
|
||||||
/* Set up RT, ENCAP and sticky MAC extended community. */
|
/* Add L3 VNI RTs and RMAC for non IPv6 link-local attributes if
|
||||||
build_evpn_route_extcomm(vpn, &attr, AFI_IP);
|
* using L3 VNI for type-2 routes also.
|
||||||
build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
|
*/
|
||||||
build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
|
if (CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS))
|
||||||
build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
|
add_l3_ecomm = 1;
|
||||||
build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
|
|
||||||
build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
|
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
|
/* Walk this VNI's route table and update local type-2 routes. For any
|
||||||
* routes updated, update corresponding entry in the global table too.
|
* 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)
|
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
|
||||||
continue;
|
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))
|
if (evpn_route_is_sticky(bgp, rn))
|
||||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||||
&attr_sticky, 0, 1, &ri,
|
&attr_sticky, 0, 1, &ri,
|
||||||
@ -1550,19 +1560,6 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
|||||||
else
|
else
|
||||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||||
&attr, 0, 1, &ri, 0);
|
&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
|
/* 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. */
|
/* Unintern temporary. */
|
||||||
aspath_unintern(&attr.aspath);
|
aspath_unintern(&attr.aspath);
|
||||||
aspath_unintern(&attr_ip6.aspath);
|
|
||||||
aspath_unintern(&attr_sticky.aspath);
|
aspath_unintern(&attr_sticky.aspath);
|
||||||
aspath_unintern(&attr_sticky_ip6.aspath);
|
|
||||||
aspath_unintern(&attr_def_gw.aspath);
|
aspath_unintern(&attr_def_gw.aspath);
|
||||||
aspath_unintern(&attr_def_gw_ip6.aspath);
|
aspath_unintern(&attr_ip6_ll.aspath);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1791,6 +1786,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||||||
{
|
{
|
||||||
struct bgp_node *rn;
|
struct bgp_node *rn;
|
||||||
struct bgp_info *ri;
|
struct bgp_info *ri;
|
||||||
|
struct attr attr;
|
||||||
struct attr *attr_new;
|
struct attr *attr_new;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
@ -1827,6 +1823,15 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||||||
} else
|
} else
|
||||||
return 0;
|
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. */
|
/* Check if route entry is already present. */
|
||||||
for (ri = rn->info; ri; ri = ri->next)
|
for (ri = rn->info; ri; ri = ri->next)
|
||||||
if (ri->extra
|
if (ri->extra
|
||||||
@ -1835,7 +1840,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||||||
|
|
||||||
if (!ri) {
|
if (!ri) {
|
||||||
/* Add (or update) attribute to hash. */
|
/* 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. */
|
/* Create new route with its attribute. */
|
||||||
ri = info_make(parent_ri->type, parent_ri->sub_type, 0,
|
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);
|
bgp_info_add(rn, ri);
|
||||||
} else {
|
} else {
|
||||||
if (attrhash_cmp(ri->attr, parent_ri->attr)
|
if (attrhash_cmp(ri->attr, &attr)
|
||||||
&& !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
|
&& !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
|
||||||
bgp_unlock_node(rn);
|
bgp_unlock_node(rn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* The attribute has changed. */
|
/* The attribute has changed. */
|
||||||
/* Add (or update) attribute to hash. */
|
/* Add (or update) attribute to hash. */
|
||||||
attr_new = bgp_attr_intern(parent_ri->attr);
|
attr_new = bgp_attr_intern(&attr);
|
||||||
|
|
||||||
/* Restore route, if needed. */
|
/* Restore route, if needed. */
|
||||||
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
|
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
|
||||||
bgp_info_restore(rn, ri);
|
bgp_info_restore(rn, ri);
|
||||||
|
|
||||||
/* Mark if nexthop has changed. */
|
/* 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);
|
SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED);
|
||||||
|
|
||||||
/* Unintern existing, set to new. */
|
/* 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)
|
static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
|
||||||
{
|
{
|
||||||
/* delete all ipv4 routes and withdraw from peers */
|
/* 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 */
|
/* 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
|
/* 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)
|
static void update_advertise_vrf_routes(struct bgp *bgp_vrf)
|
||||||
{
|
{
|
||||||
/* update all ipv4 routes */
|
/* 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 */
|
/* 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;
|
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 */
|
/* Make prefix_rd */
|
||||||
prd.family = AF_UNSPEC;
|
prd.family = AF_UNSPEC;
|
||||||
prd.prefixlen = 64;
|
prd.prefixlen = 64;
|
||||||
@ -3214,10 +3240,6 @@ void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
|||||||
struct prefix_evpn evp;
|
struct prefix_evpn evp;
|
||||||
char buf[PREFIX_STRLEN];
|
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);
|
build_type5_prefix_from_ip_prefix(&evp, p);
|
||||||
ret = delete_evpn_type5_route(bgp_vrf, &evp);
|
ret = delete_evpn_type5_route(bgp_vrf, &evp);
|
||||||
if (ret) {
|
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_node *rn = NULL;
|
||||||
struct bgp_info *ri;
|
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];
|
table = bgp_vrf->rib[afi][safi];
|
||||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||||
/* Only care about "selected" routes - non-imported. */
|
/* Only care about "selected" routes - non-imported. */
|
||||||
@ -3267,11 +3285,7 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct prefix_evpn evp;
|
struct prefix_evpn evp;
|
||||||
char buf[PREFIX_STRLEN];
|
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);
|
build_type5_prefix_from_ip_prefix(&evp, p);
|
||||||
ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
|
ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
|
||||||
if (ret)
|
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_node *rn = NULL;
|
||||||
struct bgp_info *ri;
|
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];
|
table = bgp_vrf->rib[afi][safi];
|
||||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||||
/* Need to identify the "selected" route entry to use its
|
/* Need to identify the "selected" route entry to use its
|
||||||
|
@ -55,6 +55,25 @@ static inline vni_t label2vni(mpls_label_t *label)
|
|||||||
return vni;
|
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,
|
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||||
struct prefix *p,
|
struct prefix *p,
|
||||||
struct attr *src_attr, afi_t afi,
|
struct attr *src_attr, afi_t afi,
|
||||||
|
@ -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,
|
static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
|
||||||
struct prefix *ip)
|
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;
|
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)
|
if (afi == AFI_IP &&
|
||||||
return 0;
|
CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
|
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4))
|
||||||
if (afi == AFI_IP
|
|
||||||
&& CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
else if (afi == AFI_IP6 &&
|
||||||
if (afi == AFI_IP6
|
CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
&& CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2419,7 +2419,50 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
|
|||||||
/*
|
/*
|
||||||
* evpn - enable advertisement of default g/w
|
* 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)
|
if (vpn->advertise_subnet)
|
||||||
return;
|
return;
|
||||||
@ -2612,6 +2655,43 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
|
|||||||
return CMD_SUCCESS;
|
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,
|
DEFUN (bgp_evpn_advertise_vni_subnet,
|
||||||
bgp_evpn_advertise_vni_subnet_cmd,
|
bgp_evpn_advertise_vni_subnet_cmd,
|
||||||
"advertise-subnet",
|
"advertise-subnet",
|
||||||
@ -2631,14 +2711,6 @@ DEFUN (bgp_evpn_advertise_vni_subnet,
|
|||||||
if (!bgp_vrf)
|
if (!bgp_vrf)
|
||||||
return CMD_WARNING;
|
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);
|
evpn_set_advertise_subnet(bgp, vpn);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -2711,19 +2783,23 @@ DEFUN (bgp_evpn_advertise_type5,
|
|||||||
/* if we are already advertising ipv4 prefix as type-5
|
/* if we are already advertising ipv4 prefix as type-5
|
||||||
* nothing to do
|
* nothing to do
|
||||||
*/
|
*/
|
||||||
if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
|
if (!rmap_changed &&
|
||||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
|
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
|
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
|
||||||
return CMD_WARNING;
|
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 {
|
} else {
|
||||||
|
|
||||||
/* if we are already advertising ipv6 prefix as type-5
|
/* if we are already advertising ipv6 prefix as type-5
|
||||||
* nothing to do
|
* nothing to do
|
||||||
*/
|
*/
|
||||||
if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
|
if (!rmap_changed &&
|
||||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
|
CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
|
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
|
||||||
return CMD_WARNING;
|
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) {
|
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_afi(argv, argc, &idx_afi, &afi);
|
||||||
argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
|
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,
|
vty_out(vty,
|
||||||
"%%only ipv4 or ipv6 address families are supported");
|
"%%only ipv4 or ipv6 address families are supported");
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
@ -2780,25 +2856,25 @@ DEFUN (no_bgp_evpn_advertise_type5,
|
|||||||
|
|
||||||
if (afi == AFI_IP) {
|
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
|
* nothing to do
|
||||||
*/
|
*/
|
||||||
if (CHECK_FLAG(bgp_vrf->vrf_flags,
|
if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) {
|
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
|
||||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
||||||
UNSET_FLAG(bgp_vrf->vrf_flags,
|
UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
|
BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* if we are already advertising ipv6 prefix as type-5
|
/* if we are not advertising ipv6 prefix as type-5
|
||||||
* nothing to do
|
* nothing to do
|
||||||
*/
|
*/
|
||||||
if (CHECK_FLAG(bgp_vrf->vrf_flags,
|
if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
|
||||||
BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) {
|
BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
|
||||||
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
|
||||||
UNSET_FLAG(bgp_vrf->vrf_flags,
|
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)
|
if (bgp->advertise_gw_macip)
|
||||||
vty_out(vty, " advertise-default-gw\n");
|
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");
|
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");
|
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))
|
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
|
||||||
vty_out(vty, " rd %s\n",
|
vty_out(vty, " rd %s\n",
|
||||||
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
|
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, &no_bgp_evpn_advertise_default_gw_cmd);
|
||||||
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_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, &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. */
|
/* "show bgp l2vpn evpn" commands. */
|
||||||
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
|
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_str[];
|
||||||
extern const char *bgp_origin_long_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,
|
struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
|
||||||
safi_t safi, struct prefix *p,
|
safi_t safi, struct prefix *p,
|
||||||
struct prefix_rd *prd)
|
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 */
|
/* advertise/withdraw type-5 routes */
|
||||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||||
if (new_select
|
if (advertise_type5_routes(bgp, afi) && new_select &&
|
||||||
&& (!new_select->extra || !new_select->extra->parent))
|
(!new_select->extra || !new_select->extra->parent))
|
||||||
bgp_evpn_advertise_type5_route(
|
bgp_evpn_advertise_type5_route(bgp, &rn->p,
|
||||||
bgp, &rn->p, new_select->attr, afi, safi);
|
new_select->attr,
|
||||||
else if (old_select
|
afi, safi);
|
||||||
&& (!old_select->extra || !old_select->extra->parent))
|
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);
|
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_ext_community = NULL;
|
||||||
json_object *json_lcommunity = NULL;
|
json_object *json_lcommunity = NULL;
|
||||||
json_object *json_last_update = NULL;
|
json_object *json_last_update = NULL;
|
||||||
|
json_object *json_pmsi = NULL;
|
||||||
json_object *json_nexthop_global = NULL;
|
json_object *json_nexthop_global = NULL;
|
||||||
json_object *json_nexthop_ll = NULL;
|
json_object *json_nexthop_ll = NULL;
|
||||||
json_object *json_nexthops = 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);
|
json_last_update);
|
||||||
} else
|
} else
|
||||||
vty_out(vty, " Last update: %s", ctime(&tbuf));
|
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
|
/* 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_compile,
|
||||||
route_match_ip_route_source_prefix_list_free};
|
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 mac address MAC_ACCESS_LIST' */
|
||||||
|
|
||||||
/* Match function should return 1 if match is success else return
|
/* Match function should return 1 if match is success else return
|
||||||
@ -3254,6 +3272,29 @@ DEFUN (no_match_evpn_vni,
|
|||||||
RMAP_EVENT_MATCH_DELETED);
|
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,
|
DEFUN (match_peer,
|
||||||
match_peer_cmd,
|
match_peer_cmd,
|
||||||
"match peer <A.B.C.D|X:X::X:X|WORD>",
|
"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_mac_address_cmd);
|
||||||
route_map_install_match(&route_match_evpn_vni_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_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_ip_nexthop_cmd);
|
||||||
route_map_install_set(&route_set_local_pref_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, &no_match_evpn_vni_cmd);
|
||||||
install_element(RMAP_NODE, &match_evpn_route_type_cmd);
|
install_element(RMAP_NODE, &match_evpn_route_type_cmd);
|
||||||
install_element(RMAP_NODE, &no_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, &match_aspath_cmd);
|
||||||
install_element(RMAP_NODE, &no_match_aspath_cmd);
|
install_element(RMAP_NODE, &no_match_aspath_cmd);
|
||||||
|
@ -7534,16 +7534,14 @@ static void bgp_pthreads_init()
|
|||||||
.id = PTHREAD_IO,
|
.id = PTHREAD_IO,
|
||||||
.start = frr_pthread_attr_default.start,
|
.start = frr_pthread_attr_default.start,
|
||||||
.stop = frr_pthread_attr_default.stop,
|
.stop = frr_pthread_attr_default.stop,
|
||||||
.name = "BGP I/O thread",
|
|
||||||
};
|
};
|
||||||
struct frr_pthread_attr ka = {
|
struct frr_pthread_attr ka = {
|
||||||
.id = PTHREAD_KEEPALIVES,
|
.id = PTHREAD_KEEPALIVES,
|
||||||
.start = bgp_keepalives_start,
|
.start = bgp_keepalives_start,
|
||||||
.stop = bgp_keepalives_stop,
|
.stop = bgp_keepalives_stop,
|
||||||
.name = "BGP Keepalives thread",
|
|
||||||
};
|
};
|
||||||
frr_pthread_new(&io);
|
frr_pthread_new(&io, "BGP I/O thread");
|
||||||
frr_pthread_new(&ka);
|
frr_pthread_new(&ka, "BGP Keepalives thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgp_pthreads_run()
|
void bgp_pthreads_run()
|
||||||
|
18
bgpd/bgpd.h
@ -319,6 +319,13 @@ struct bgp {
|
|||||||
#define BGP_CONFIG_DAMPENING (1 << 0)
|
#define BGP_CONFIG_DAMPENING (1 << 0)
|
||||||
#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 1)
|
#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. */
|
/* Route table for next-hop lookup cache. */
|
||||||
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
||||||
|
|
||||||
@ -430,12 +437,11 @@ struct bgp {
|
|||||||
/* vrf flags */
|
/* vrf flags */
|
||||||
uint32_t vrf_flags;
|
uint32_t vrf_flags;
|
||||||
#define BGP_VRF_AUTO (1 << 0)
|
#define BGP_VRF_AUTO (1 << 0)
|
||||||
#define BGP_VRF_ADVERTISE_IPV4_IN_EVPN (1 << 1)
|
#define BGP_VRF_IMPORT_RT_CFGD (1 << 1)
|
||||||
#define BGP_VRF_ADVERTISE_IPV6_IN_EVPN (1 << 2)
|
#define BGP_VRF_EXPORT_RT_CFGD (1 << 2)
|
||||||
#define BGP_VRF_IMPORT_RT_CFGD (1 << 3)
|
#define BGP_VRF_RD_CFGD (1 << 3)
|
||||||
#define BGP_VRF_EXPORT_RT_CFGD (1 << 4)
|
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4)
|
||||||
#define BGP_VRF_RD_CFGD (1 << 5)
|
|
||||||
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 6)
|
|
||||||
|
|
||||||
/* unique ID for auto derivation of RD for this vrf */
|
/* unique ID for auto derivation of RD for this vrf */
|
||||||
uint16_t vrf_rd_id;
|
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]))
|
AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
|
||||||
AC_ARG_ENABLE([clippy-only],
|
AC_ARG_ENABLE([clippy-only],
|
||||||
AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
|
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"], [
|
AS_IF([test "${enable_clippy_only}" != "yes"], [
|
||||||
AC_CHECK_HEADERS(json-c/json.h)
|
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])
|
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 -----------------------------------
|
||||||
dnl Add extra version string to package
|
dnl Add extra version string to package
|
||||||
dnl name, string and version fields.
|
dnl name, string and version fields.
|
||||||
@ -1872,27 +1882,10 @@ AC_CONFIG_FILES([Makefile
|
|||||||
redhat/frr.spec
|
redhat/frr.spec
|
||||||
debianpkg/Makefile
|
debianpkg/Makefile
|
||||||
debianpkg/changelog
|
debianpkg/changelog
|
||||||
|
alpine/APKBUILD
|
||||||
snapcraft/snapcraft.yaml
|
snapcraft/snapcraft.yaml
|
||||||
lib/version.h
|
lib/version.h
|
||||||
tests/lib/cli/test_cli.refout
|
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/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
|
||||||
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
|
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
|
||||||
pkgsrc/eigrpd.sh])
|
pkgsrc/eigrpd.sh])
|
||||||
|
@ -27,6 +27,9 @@ MULTIPATH ?= 256
|
|||||||
WANT_FRR_USER ?= frr
|
WANT_FRR_USER ?= frr
|
||||||
WANT_FRR_VTY_GROUP ?= frrvty
|
WANT_FRR_VTY_GROUP ?= frrvty
|
||||||
|
|
||||||
|
# Don't build PDF docs by default
|
||||||
|
GENERATE_PDF ?= 0
|
||||||
|
|
||||||
#
|
#
|
||||||
####################################
|
####################################
|
||||||
|
|
||||||
@ -135,18 +138,11 @@ override_dh_auto_configure:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
override_dh_auto_build:
|
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)
|
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
|
endif
|
||||||
rm -vf doc/frr.info
|
rm -vf doc/user/_build/texinfo/frr.info
|
||||||
dh_auto_build -- -C doc frr.info
|
dh_auto_build -- -C doc info
|
||||||
rm -vf doc/frr.info.html*
|
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
@ -5,18 +5,6 @@ usr/include/frr/
|
|||||||
usr/lib/
|
usr/lib/
|
||||||
tools/frr etc/init.d/
|
tools/frr etc/init.d/
|
||||||
usr/share/doc/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/mtracebis.8
|
|
||||||
usr/share/snmp/mibs/
|
usr/share/snmp/mibs/
|
||||||
tools/etc/* etc/
|
tools/etc/* etc/
|
||||||
tools/*.service lib/systemd/system
|
tools/*.service lib/systemd/system
|
||||||
|
@ -27,6 +27,9 @@ MULTIPATH ?= 256
|
|||||||
WANT_FRR_USER ?= frr
|
WANT_FRR_USER ?= frr
|
||||||
WANT_FRR_VTY_GROUP ?= frrvty
|
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:
|
override_dh_auto_build:
|
||||||
#dh_auto_build
|
#dh_auto_build
|
||||||
$(MAKE)
|
$(MAKE)
|
||||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
|
||||||
|
|
||||||
|
|
||||||
# doc/ is a bit crazy
|
# doc/ is a bit crazy
|
||||||
ifeq ($(GENERATE_PDF), 1)
|
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
|
endif
|
||||||
rm -vf doc/frr.info
|
rm -vf doc/_build/texinfo/frr.info
|
||||||
dh_auto_build -- -C doc frr.info
|
dh_auto_build -- -C doc info
|
||||||
rm -vf doc/frr.info.html*
|
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ Priority: optional
|
|||||||
Maintainer: Nobody <nobody@frrouting.org>
|
Maintainer: Nobody <nobody@frrouting.org>
|
||||||
Uploaders: Nobody <nobody@frrouting.org>
|
Uploaders: Nobody <nobody@frrouting.org>
|
||||||
XSBC-Original-Maintainer: <maintainers@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
|
Standards-Version: 3.9.6
|
||||||
Homepage: http://www.frrouting.org/
|
Homepage: http://www.frrouting.org/
|
||||||
|
|
||||||
|
@ -2,7 +2,5 @@ AUTHORS
|
|||||||
NEWS
|
NEWS
|
||||||
README
|
README
|
||||||
REPORTING-BUGS
|
REPORTING-BUGS
|
||||||
doc/BGP-TypeCode
|
doc/user/*.rst
|
||||||
doc/draft-zebra-00.txt
|
doc/figures/*.png
|
||||||
doc/mpls/
|
|
||||||
bgpd/BGP4-MIB.txt
|
|
||||||
|
@ -1 +1 @@
|
|||||||
doc/frr.info*
|
doc/user/_build/texinfo/frr.info
|
||||||
|
@ -1,2 +1 @@
|
|||||||
usr/share/info
|
doc/user/_build/texinfo/*.png usr/share/info
|
||||||
doc/*.png usr/share/info
|
|
||||||
|
@ -5,20 +5,7 @@ usr/include/frr/
|
|||||||
usr/lib/
|
usr/lib/
|
||||||
tools/frr usr/lib/frr
|
tools/frr usr/lib/frr
|
||||||
usr/share/doc/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/
|
usr/share/snmp/mibs/
|
||||||
tools/etc/* etc/
|
tools/etc/* etc/
|
||||||
tools/*.service lib/systemd/system
|
tools/*.service lib/systemd/system
|
||||||
debian/frr.conf usr/lib/tmpfiles.d
|
debian/frr.conf usr/lib/tmpfiles.d
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
doc/bgpd.8
|
doc/manpages/_build/man/frr.1
|
||||||
doc/ospf6d.8
|
doc/manpages/_build/man/bgpd.8
|
||||||
doc/ospfd.8
|
doc/manpages/_build/man/pimd.8
|
||||||
doc/ripd.8
|
doc/manpages/_build/man/eigrpd.8
|
||||||
doc/ripngd.8
|
doc/manpages/_build/man/ldpd.8
|
||||||
doc/vtysh.1
|
doc/manpages/_build/man/nhrpd.8
|
||||||
doc/zebra.8
|
doc/manpages/_build/man/ospf6d.8
|
||||||
doc/isisd.8
|
doc/manpages/_build/man/ospfd.8
|
||||||
doc/watchfrr.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_USER ?= frr
|
||||||
WANT_FRR_VTY_GROUP ?= frrvty
|
WANT_FRR_VTY_GROUP ?= frrvty
|
||||||
|
|
||||||
|
# Don't build PDF docs by default
|
||||||
|
GENERATE_PDF ?= 0
|
||||||
|
|
||||||
#
|
#
|
||||||
####################################
|
####################################
|
||||||
|
|
||||||
@ -136,18 +139,12 @@ override_dh_auto_configure:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
#dh_auto_build
|
|
||||||
$(MAKE)
|
|
||||||
dh_auto_build -- -C doc draft-zebra-00.txt
|
|
||||||
|
|
||||||
|
|
||||||
# doc/ is a bit crazy
|
# doc/ is a bit crazy
|
||||||
ifeq ($(GENERATE_PDF), 1)
|
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
|
endif
|
||||||
rm -vf doc/frr.info
|
rm -vf doc/user/_build/texinfo/frr.info
|
||||||
dh_auto_build -- -C doc frr.info
|
dh_auto_build -- -C doc info
|
||||||
rm -vf doc/frr.info.html*
|
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|
||||||
|
9
doc/.gitignore
vendored
@ -2,13 +2,6 @@ Makefile
|
|||||||
Makefile.in
|
Makefile.in
|
||||||
mdate-sh
|
mdate-sh
|
||||||
draft-zebra-00.txt
|
draft-zebra-00.txt
|
||||||
frr.info-*
|
|
||||||
zebra.html
|
|
||||||
defines.texi
|
|
||||||
version.texi
|
|
||||||
texinfo.tex
|
|
||||||
frr.html
|
|
||||||
frr.info
|
|
||||||
*.pdf
|
*.pdf
|
||||||
*.eps
|
*.eps
|
||||||
frr.ps
|
frr.ps
|
||||||
@ -28,8 +21,6 @@ stamp-vti
|
|||||||
*.toc
|
*.toc
|
||||||
*.tp
|
*.tp
|
||||||
*.vr
|
*.vr
|
||||||
*.8
|
|
||||||
*.1
|
|
||||||
.arch-inventory
|
.arch-inventory
|
||||||
.arch-ids
|
.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.
|
## Process this file with automake to produce Makefile.in.
|
||||||
|
|
||||||
# Dia, the version i have at least, doesn't do very good EPS output
|
# Pass down make invocation to each subdirectory.
|
||||||
# (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.
|
|
||||||
#
|
#
|
||||||
# Here we use 'convert' from the well known 'ImageMagick' package
|
# Each of these directories contains a Sphinx-generated Makefile that has been
|
||||||
# to do conversion from png to eps/pdf for figures.
|
# modified to implement all the targets required by Automake, as documented in
|
||||||
# PDF form is required for frr.pdf, using PDFTex at least.
|
# the 'Third-Party Makefiles' section of the Automake docs.
|
||||||
#
|
#
|
||||||
# TeX implementation, which we depend on already anyway.
|
# 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
|
||||||
# dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf
|
# asked for. See comment further down.
|
||||||
SUFFIXES = .png .eps .dia .pdf
|
|
||||||
DIATOPNG = dia -t png -e
|
|
||||||
DIATOEPS = dia -t eps -e
|
|
||||||
PNGTOEPS = convert -antialias -contrast -despeckle
|
|
||||||
PNGTOPDF = $(PNGTOEPS)
|
|
||||||
EPSTOPDF = epstopdf
|
|
||||||
|
|
||||||
VNCFIGURES_PNG =
|
# Sphinx is not designed to be invoked multiple times against the same toctree.
|
||||||
VNCFIGURES_DIA = -vnc-mesh -vnc-frr-route-reflector \
|
.NOTPARALLEL:
|
||||||
-vnc-commercial-route-reflector -vnc-redundant-route-reflectors \
|
|
||||||
-vnc-gw -vnc-gw-rr
|
|
||||||
|
|
||||||
# TODO: A target that creates an empty text file for each member of
|
SUBDIRS = manpages user
|
||||||
# VNCFIGURES_TXT
|
AM_MAKEFLAGS = DESTDIR=${DESTDIR} infodir=${infodir} doczdir=${abs_srcdir}
|
||||||
VNCFIGURES_TXT = $(VNCFIGURES:%.png=%.txt)
|
|
||||||
|
|
||||||
# The figure sources
|
MANPAGE_BUILDDIR = manpages/_build/man
|
||||||
figures_names_parts = -normal-processing -rs-processing \
|
|
||||||
_topologies_full _topologies_rs \
|
|
||||||
$(VNCFIGURES_DIA)
|
|
||||||
|
|
||||||
figures_sources = $(figures_names_parts:%=fig%.dia)
|
# This is a hack, see comment further down.
|
||||||
figures_png = $(figures_names_parts:%=fig%.png) $(VNCFIGURES_PNG)
|
man_MANS = $(MANPAGE_BUILDDIR)/frr.1
|
||||||
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
|
|
||||||
|
|
||||||
if PIMD
|
if PIMD
|
||||||
man_MANS += pimd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/pimd.8
|
||||||
man_MANS += mtracebis.8
|
man_MANS += $(MANPAGE_BUILDDIR)/mtracebis.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BGPD
|
if BGPD
|
||||||
man_MANS += bgpd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/bgpd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ISISD
|
if ISISD
|
||||||
man_MANS += isisd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/isisd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if OSPF6D
|
if OSPF6D
|
||||||
man_MANS += ospf6d.8
|
man_MANS += $(MANPAGE_BUILDDIR)/ospf6d.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if OSPFCLIENT
|
if OSPFCLIENT
|
||||||
man_MANS += ospfclient.8
|
man_MANS += $(MANPAGE_BUILDDIR)/ospfclient.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if OSPFD
|
if OSPFD
|
||||||
man_MANS += ospfd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/ospfd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if LDPD
|
if LDPD
|
||||||
man_MANS += ldpd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/ldpd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if RIPD
|
if RIPD
|
||||||
man_MANS += ripd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/ripd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if RIPNGD
|
if RIPNGD
|
||||||
man_MANS += ripngd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/ripngd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if NHRPD
|
if NHRPD
|
||||||
man_MANS += nhrpd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/nhrpd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if VTYSH
|
if VTYSH
|
||||||
man_MANS += vtysh.1
|
man_MANS += $(MANPAGE_BUILDDIR)/vtysh.1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if WATCHFRR
|
if WATCHFRR
|
||||||
man_MANS += watchfrr.8
|
man_MANS += $(MANPAGE_BUILDDIR)/watchfrr.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ZEBRA
|
if ZEBRA
|
||||||
man_MANS += zebra.8
|
man_MANS += $(MANPAGE_BUILDDIR)/zebra.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if EIGRPD
|
if EIGRPD
|
||||||
man_MANS += eigrpd.8
|
man_MANS += $(MANPAGE_BUILDDIR)/eigrpd.8
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.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
|
||||||
bgpd.8.in \
|
# given in groff source and so these facilities are limited to simply
|
||||||
isisd.8.in \
|
# specifying the path to the groff sources in a special variable. There is no
|
||||||
ospf6d.8.in \
|
# target for building manpages that can be extended, as there are for pdf,
|
||||||
ospfclient.8.in \
|
# html, dvi, etc. Unfortunately this leaves us with hijacking the
|
||||||
ospfd.8.in \
|
# 'install-data' and 'all' targets in the 3rd-party Makefile in manpages/ to
|
||||||
ldpd.8.in \
|
# make sure manpages are always built, and then using the special Automake
|
||||||
ripd.8.in \
|
# variable defined above in order to take advantage of automatic installation.
|
||||||
ripngd.8.in \
|
#
|
||||||
pimd.8.in \
|
# However, it is conceivable that someone may want to build just the manpages,
|
||||||
mtracebis.8.in \
|
# so here's an explicit target for that.
|
||||||
nhrpd.8.in \
|
man:
|
||||||
vtysh.1.in \
|
$(MAKE) -C manpages man
|
||||||
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)
|
|
||||||
|
|
||||||
draft-zebra-00.txt: draft-zebra-00.ms
|
# Automake automatically defines targets for various document formats. All of
|
||||||
groff -T ascii -ms $< > $@
|
# 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
|
developer-pdf:
|
||||||
html-local: $(HTMLS)
|
$(MAKE) -C developer latexpdf
|
||||||
if test -d $(HTMLS) ; then \
|
|
||||||
cp -p $(figures_png) $(HTMLS) ; \
|
developer-html:
|
||||||
else \
|
$(MAKE) -C developer html
|
||||||
echo "$(HTMLS) is not a directory. Make it so, the rerun make."; \
|
|
||||||
fi
|
# 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,46 +1,67 @@
|
|||||||
Building FRR on CentOS 6 from Git Source
|
CentOS 6
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
(As an alternative to this installation, you may prefer to create a FRR
|
(As an alternative to this installation, you may prefer to create a FRR
|
||||||
rpm package yourself and install that package instead. See instructions
|
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:
|
CentOS 6 restrictions:
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
- PIMd is not supported on `CentOS 6`. Upgrade to `CentOS 7` if PIMd is
|
- PIMd is not supported on ``CentOS 6``. Upgrade to ``CentOS 7`` if
|
||||||
needed
|
PIMd is needed
|
||||||
- MPLS is not supported on `CentOS 6`. MPLS requires Linux Kernel 4.5 or
|
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
|
||||||
higher (LDP can be built, but may have limited use without MPLS)
|
or higher (LDP can be built, but may have limited use without MPLS)
|
||||||
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
- Zebra is unable to detect what bridge/vrf an interface is associcated
|
||||||
with (IFLA_INFO_SLAVE_KIND does not exist in the kernel headers, you
|
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
|
||||||
can use a newer kernel + headers to get this functionality)
|
you can use a newer kernel + headers to get this functionality)
|
||||||
- frr_reload.py will not work, as this requires Python 2.7, and CentOS 6
|
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
|
||||||
only has 2.6. You can install Python 2.7 via IUS, but it won't work
|
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.
|
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
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo yum install git autoconf automake libtool make gawk \
|
sudo yum install git autoconf automake libtool make gawk \
|
||||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||||
json-c-devel pam-devel flex epel-release perl-XML-LibXML \
|
json-c-devel pam-devel flex epel-release perl-XML-LibXML \
|
||||||
c-ares-devel
|
c-ares-devel
|
||||||
|
|
||||||
Install newer version of bison (CentOS 6 package source is too old) from
|
Install newer version of bison (CentOS 6 package source is too old) from
|
||||||
CentOS 7
|
CentOS 7
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo yum install rpm-build
|
sudo yum install rpm-build
|
||||||
curl -O http://vault.centos.org/7.0.1406/os/Source/SPackages/bison-2.7-4.el7.src.rpm
|
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
|
rpmbuild --rebuild ./bison-2.7-4.el7.src.rpm
|
||||||
sudo yum install ./rpmbuild/RPMS/x86_64/bison-2.7-4.el6.x86_64.rpm
|
sudo yum install ./rpmbuild/RPMS/x86_64/bison-2.7-4.el6.x86_64.rpm
|
||||||
rm -rf rpmbuild
|
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
|
curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
|
||||||
tar xvf autoconf-2.69.tar.gz
|
tar xvf autoconf-2.69.tar.gz
|
||||||
@ -49,7 +70,7 @@ Install newer version of autoconf and automake (Package versions are too old)
|
|||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
curl -O http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
|
curl -O http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
|
||||||
tar xvf automake-1.15.tar.gz
|
tar xvf automake-1.15.tar.gz
|
||||||
cd automake-1.15
|
cd automake-1.15
|
||||||
@ -58,35 +79,69 @@ Install newer version of autoconf and automake (Package versions are too old)
|
|||||||
sudo make install
|
sudo make install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
Install `Python 2.7` in parallel to default 2.6.
|
Install ``Python 2.7`` in parallel to default 2.6. Make sure you've
|
||||||
Make sure you've install EPEL (`epel-release` as above). Then install current
|
install EPEL (``epel-release`` as above). Then install current
|
||||||
`python27`, `python27-devel` and `pytest`
|
``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 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 rpm -ivh https://centos6.iuscommunity.org/ius-release.rpm
|
||||||
sudo yum install python27 python27-pip python27-devel
|
sudo yum install python27 python27-pip python27-devel
|
||||||
sudo pip2.7 install pytest
|
sudo pip2.7 install pytest
|
||||||
|
|
||||||
Please note that `CentOS 6` needs to keep python pointing to version 2.6
|
Please note that ``CentOS 6`` needs to keep python pointing to version
|
||||||
for `yum` to keep working, so don't create a symlink for python2.7 to python
|
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)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 92 frr
|
sudo groupadd -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvt
|
sudo groupadd -r -g 85 frrvt
|
||||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
-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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -116,11 +171,15 @@ an example.)
|
|||||||
--enable-babeld \
|
--enable-babeld \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make SPHINXBUILD=sphinx-build2.7
|
||||||
make check PYTHON=/usr/bin/python2.7
|
make check PYTHON=/usr/bin/python2.7 SPHINXBUILD=sphinx-build2.7
|
||||||
sudo make install
|
sudo make SPHINXBUILD=sphinx-build2.7 install
|
||||||
|
|
||||||
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
|
||||||
sudo mkdir /var/log/frr
|
sudo mkdir /var/log/frr
|
||||||
sudo mkdir /etc/frr
|
sudo mkdir /etc/frr
|
||||||
sudo touch /etc/frr/zebra.conf
|
sudo touch /etc/frr/zebra.conf
|
||||||
@ -138,20 +197,28 @@ an example.)
|
|||||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||||
sudo chmod 640 /etc/frr/*.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 install -p -m 644 redhat/daemons /etc/frr/
|
||||||
sudo chown frr:frr /etc/frr/daemons
|
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.
|
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||||
Enable the daemons as required by changing the value to `yes`
|
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)
|
settings)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Controls IP packet forwarding
|
# Controls IP packet forwarding
|
||||||
net.ipv4.ip_forward = 1
|
net.ipv4.ip_forward = 1
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
@ -161,14 +228,28 @@ settings)
|
|||||||
|
|
||||||
Load the modifed sysctl's on the system:
|
Load the modifed sysctl's on the system:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
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 install -p -m 755 redhat/frr.init /etc/init.d/frr
|
||||||
sudo chkconfig --add frr
|
sudo chkconfig --add frr
|
||||||
|
|
||||||
### Enable frr daemon at startup
|
Enable frr daemon at startup
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo chkconfig frr on
|
sudo chkconfig frr on
|
||||||
|
|
||||||
### Start FRR manually (or reboot)
|
Start FRR manually (or reboot)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo /etc/init.d/frr start
|
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
|
(As an alternative to this installation, you may prefer to create a FRR
|
||||||
rpm package yourself and install that package instead. See instructions
|
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:
|
CentOS 7 restrictions:
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
- MPLS is not supported on `CentOS 7` with default kernel. MPLS requires
|
- MPLS is not supported on ``CentOS 7`` with default kernel. MPLS
|
||||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||||
without MPLS)
|
limited use without MPLS)
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo yum install git autoconf automake libtool make gawk \
|
sudo yum install git autoconf automake libtool make gawk \
|
||||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||||
json-c-devel pam-devel bison flex pytest c-ares-devel \
|
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)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 92 frr
|
sudo groupadd -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvt
|
sudo groupadd -r -g 85 frrvt
|
||||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
-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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -73,7 +82,11 @@ an example.)
|
|||||||
make check
|
make check
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /var/log/frr
|
sudo mkdir /var/log/frr
|
||||||
sudo mkdir /etc/frr
|
sudo mkdir /etc/frr
|
||||||
sudo touch /etc/frr/zebra.conf
|
sudo touch /etc/frr/zebra.conf
|
||||||
@ -92,20 +105,28 @@ an example.)
|
|||||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||||
sudo chmod 640 /etc/frr/*.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 install -p -m 644 redhat/daemons /etc/frr/
|
||||||
sudo chown frr:frr /etc/frr/daemons
|
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.
|
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||||
Enable the daemons as required by changing the value to `yes`
|
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:
|
following content:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Sysctl for routing
|
# Sysctl for routing
|
||||||
#
|
#
|
||||||
# Routing: We need to forward packets
|
# Routing: We need to forward packets
|
||||||
@ -114,17 +135,35 @@ following content:
|
|||||||
|
|
||||||
Load the modifed sysctl's on the system:
|
Load the modifed sysctl's on the system:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
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 644 redhat/frr.service /usr/lib/systemd/system/frr.service
|
||||||
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
|
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
|
sudo systemctl preset frr.service
|
||||||
|
|
||||||
### Enable required frr at startup
|
Enable required frr at startup
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo systemctl enable frr
|
sudo systemctl enable frr
|
||||||
|
|
||||||
### Reboot or start FRR manually
|
Reboot or start FRR manually
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo systemctl start frr
|
sudo systemctl start frr
|
@ -1,33 +1,40 @@
|
|||||||
Building FRR on Debian 8 from Git Source
|
Debian 8
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
Debian 8 restrictions:
|
Debian 8 restrictions:
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
- MPLS is not supported on `Debian 8` with default kernel. MPLS requires
|
- MPLS is not supported on ``Debian 8`` with default kernel. MPLS
|
||||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||||
without MPLS)
|
limited use without MPLS)
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo apt-get install git autoconf automake libtool make gawk \
|
sudo apt-get install git autoconf automake libtool make gawk \
|
||||||
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
|
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
|
Install newer pytest (>3.0) from pip
|
||||||
|
|
||||||
sudo pip install pytest
|
::
|
||||||
|
|
||||||
|
sudo pip install pytest
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo addgroup --system --gid 92 frr
|
sudo addgroup --system --gid 92 frr
|
||||||
sudo addgroup --system --gid 85 frrvty
|
sudo addgroup --system --gid 85 frrvty
|
||||||
@ -35,10 +42,14 @@ any packages**
|
|||||||
--gecos "FRR suite" --shell /bin/false frr
|
--gecos "FRR suite" --shell /bin/false frr
|
||||||
sudo usermod -a -G frrvty 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
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -63,12 +74,15 @@ an example.)
|
|||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--enable-ldpd \
|
--enable-ldpd \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
sudo make install
|
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/log/frr
|
||||||
sudo install -m 775 -o frr -g frrvty -d /etc/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 frr /dev/null /etc/frr/nhrpd.conf
|
||||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.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)
|
other settings)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Uncomment the next line to enable packet forwarding for IPv4
|
# Uncomment the next line to enable packet forwarding for IPv4
|
||||||
net.ipv4.ip_forward=1
|
net.ipv4.ip_forward=1
|
||||||
|
|
||||||
@ -97,35 +114,43 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||||
|
system
|
||||||
|
|
||||||
### Troubleshooting
|
Troubleshooting
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
**Local state directory**
|
**Local state directory**
|
||||||
|
|
||||||
The local state directory must exist and have the correct permissions applied
|
The local state directory must exist and have the correct permissions
|
||||||
for the frrouting daemons to start. In the above ./configure example the
|
applied for the frrouting daemons to start. In the above ./configure
|
||||||
local state directory is set to /var/run/frr (--localstatedir=/var/run/frr)
|
example the local state directory is set to /var/run/frr
|
||||||
Debian considers /var/run/frr to be temporary and this is removed after a
|
(--localstatedir=/var/run/frr) Debian considers /var/run/frr to be
|
||||||
reboot.
|
temporary and this is removed after a reboot.
|
||||||
|
|
||||||
When using a different local state directory you need to create the new
|
When using a different local state directory you need to create the new
|
||||||
directory and change the ownership to the frr user, for example:
|
directory and change the ownership to the frr user, for example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
mkdir /var/opt/frr
|
mkdir /var/opt/frr
|
||||||
chown frr /var/opt/frr
|
chown frr /var/opt/frr
|
||||||
|
|
||||||
**Shared library error**
|
**Shared library error**
|
||||||
|
|
||||||
If you try and start any of the frrouting daemons you may see the below error
|
If you try and start any of the frrouting daemons you may see the below
|
||||||
due to the frrouting shared library directory not being found:
|
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
|
./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
|
The fix is to add the following line to /etc/ld.so.conf which will
|
||||||
reference the library directory after the system reboots. To load the library
|
continue to reference the library directory after the system reboots. To
|
||||||
directory path immediately run the ldconfig command after adding the line to
|
load the library directory path immediately run the ldconfig command
|
||||||
the file eg:
|
after adding the line to the file eg:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
echo include /usr/local/lib >> /etc/ld.so.conf
|
||||||
ldconfig
|
ldconfig
|
@ -1,4 +1,4 @@
|
|||||||
Building FRR on Debian 9 from Git Source
|
Debian 9
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
@ -6,17 +6,22 @@ Install required packages
|
|||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo apt-get install git autoconf automake libtool make \
|
sudo apt-get install git autoconf automake libtool make \
|
||||||
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
|
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)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo addgroup --system --gid 92 frr
|
sudo addgroup --system --gid 92 frr
|
||||||
sudo addgroup --system --gid 85 frrvty
|
sudo addgroup --system --gid 85 frrvty
|
||||||
@ -24,10 +29,14 @@ any packages**
|
|||||||
--gecos "FRR suite" --shell /bin/false frr
|
--gecos "FRR suite" --shell /bin/false frr
|
||||||
sudo usermod -a -G frrvty 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
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
git checkout stable/3.0
|
git checkout stable/3.0
|
||||||
@ -53,12 +62,15 @@ an example.)
|
|||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--enable-ldpd \
|
--enable-ldpd \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
sudo make install
|
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/log/frr
|
||||||
sudo install -m 755 -o frr -g frr -d /var/opt/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 frr /dev/null /etc/frr/nhrpd.conf
|
||||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.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)
|
other settings)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Uncomment the next line to enable packet forwarding for IPv4
|
# Uncomment the next line to enable packet forwarding for IPv4
|
||||||
net.ipv4.ip_forward=1
|
net.ipv4.ip_forward=1
|
||||||
|
|
||||||
@ -88,21 +103,29 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
**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
|
If you try and start any of the frrouting daemons you may see the below
|
||||||
due to the frrouting shared library directory not being found:
|
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
|
./zebra: error while loading shared libraries: libfrr.so.0: cannot open
|
||||||
reference the library directory after the system reboots. To load the library
|
shared object file: No such file or directory
|
||||||
directory path immediately run the ldconfig command after adding the line to
|
|
||||||
the file eg:
|
|
||||||
|
|
||||||
echo include /usr/local/lib >> /etc/ld.so.conf
|
The fix is to add the following line to /etc/ld.so.conf which will
|
||||||
ldconfig
|
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,37 +1,46 @@
|
|||||||
Building FRR on Fedora 24 from Git Source
|
Fedora 24
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
(As an alternative to this installation, you may prefer to create a FRR
|
(As an alternative to this installation, you may prefer to create a FRR
|
||||||
rpm package yourself and install that package instead. See instructions
|
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
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo dnf install git autoconf automake libtool make gawk \
|
sudo dnf install git autoconf automake libtool make gawk \
|
||||||
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
readline-devel texinfo net-snmp-devel groff pkgconfig \
|
||||||
json-c-devel pam-devel perl-XML-LibXML pytest bison flex \
|
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)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not
|
**This assumes you want to build and install FRR from source and not
|
||||||
using any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 92 frr
|
sudo groupadd -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvt
|
sudo groupadd -r -g 85 frrvt
|
||||||
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
sudo useradd -u 92 -g 92 -M -r -G frrvt -s /sbin/nologin \
|
||||||
-c "FRR FRRouting suite" -d /var/run/frr frr
|
-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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -60,12 +69,16 @@ an example.)
|
|||||||
--enable-eigrpd \
|
--enable-eigrpd \
|
||||||
--enable-babeld \
|
--enable-babeld \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /var/log/frr
|
sudo mkdir /var/log/frr
|
||||||
sudo mkdir /etc/frr
|
sudo mkdir /etc/frr
|
||||||
sudo touch /etc/frr/zebra.conf
|
sudo touch /etc/frr/zebra.conf
|
||||||
@ -85,21 +98,28 @@ an example.)
|
|||||||
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
sudo chown frr:frrvt /etc/frr/vtysh.conf
|
||||||
sudo chmod 640 /etc/frr/*.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 install -p -m 644 redhat/daemons /etc/frr/
|
||||||
sudo chown frr:frr /etc/frr/daemons
|
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.
|
Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
|
||||||
Enable the daemons as required by changing the value to `yes`
|
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
|
Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
|
||||||
following content:
|
following content: (Please make sure to list all interfaces with
|
||||||
(Please make sure to list all interfaces with required MPLS similar
|
required MPLS similar to ``net.mpls.conf.eth0.input=1``)
|
||||||
to `net.mpls.conf.eth0.input=1`)
|
|
||||||
|
::
|
||||||
|
|
||||||
# Sysctl for routing
|
# Sysctl for routing
|
||||||
#
|
#
|
||||||
@ -115,9 +135,14 @@ to `net.mpls.conf.eth0.input=1`)
|
|||||||
|
|
||||||
Load the modifed sysctl's on the system:
|
Load the modifed sysctl's on the system:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
|
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
|
# Load MPLS Kernel Modules
|
||||||
mpls-router
|
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:
|
And load the kernel modules on the running system:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo modprobe mpls-router mpls-iptunnel
|
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 644 redhat/frr.service /usr/lib/systemd/system/frr.service
|
||||||
sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
|
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
|
sudo systemctl enable frr
|
||||||
|
|
||||||
### Reboot or start FRR manually
|
Reboot or start FRR manually
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo systemctl start frr
|
sudo systemctl start frr
|
@ -1,46 +1,53 @@
|
|||||||
Building FRR on FreeBSD 10 from Git Source
|
FreeBSD 10
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
FreeBSD 10 restrictions:
|
FreeBSD 10 restrictions:
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||||
(4.5 or higher). LDP can be built, but may have limited use
|
(4.5 or higher). LDP can be built, but may have limited use without
|
||||||
without MPLS
|
MPLS
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages: (Allow the install of the package managment tool if this
|
||||||
(Allow the install of the package managment tool if this is first package
|
is first package install and asked)
|
||||||
install and asked)
|
|
||||||
|
::
|
||||||
|
|
||||||
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
|
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
|
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||||
installed in /usr/local/bin):
|
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
as part of the base OS which takes preference in path)
|
||||||
takes preference in path)
|
|
||||||
|
::
|
||||||
|
|
||||||
rm -f /usr/bin/flex
|
rm -f /usr/bin/flex
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not
|
**This assumes you want to build and install FRR from source and not
|
||||||
using any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr group and user
|
Add frr group and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pw groupadd frr -g 101
|
pw groupadd frr -g 101
|
||||||
pw groupadd frrvty -g 102
|
pw groupadd frrvty -g 102
|
||||||
pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
|
pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \
|
||||||
-d /usr/local/etc/frr -s /usr/sbin/nologin
|
-d /usr/local/etc/frr -s /usr/sbin/nologin
|
||||||
|
|
||||||
(You may prefer different options on configure statement. These are just
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -63,12 +70,16 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
sudo gmake install
|
sudo gmake install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /usr/local/etc/frr
|
sudo mkdir /usr/local/etc/frr
|
||||||
sudo touch /usr/local/etc/frr/zebra.conf
|
sudo touch /usr/local/etc/frr/zebra.conf
|
||||||
sudo touch /usr/local/etc/frr/bgpd.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 chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||||
sudo chmod 640 /usr/local/etc/frr/*.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
|
# Routing: We need to forward packets
|
||||||
net.inet.ip.forwarding=1
|
net.inet.ip.forwarding=1
|
||||||
net.inet6.ip6.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,37 +1,42 @@
|
|||||||
Building FRR on FreeBSD 11 from Git Source
|
FreeBSD 11
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
FreeBSD 11 restrictions:
|
FreeBSD 11 restrictions:
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||||
(4.5 or higher). LDP can be built, but may have limited use
|
(4.5 or higher). LDP can be built, but may have limited use without
|
||||||
without MPLS
|
MPLS
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages: (Allow the install of the package managment tool if this
|
||||||
(Allow the install of the package managment tool if this is first package
|
is first package install and asked)
|
||||||
install and asked)
|
|
||||||
|
::
|
||||||
|
|
||||||
pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
|
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
|
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||||
installed in /usr/local/bin):
|
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
as part of the base OS which takes preference in path)
|
||||||
takes preference in path)
|
|
||||||
|
::
|
||||||
|
|
||||||
rm -f /usr/bin/flex
|
rm -f /usr/bin/flex
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not
|
**This assumes you want to build and install FRR from source and not
|
||||||
using any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr group and user
|
Add frr group and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pw groupadd frr -g 101
|
pw groupadd frr -g 101
|
||||||
pw groupadd frrvty -g 102
|
pw groupadd frrvty -g 102
|
||||||
@ -41,6 +46,8 @@ using any packages**
|
|||||||
(You may prefer different options on configure statement. These are just
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -63,12 +70,16 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
sudo gmake install
|
sudo gmake install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /usr/local/etc/frr
|
sudo mkdir /usr/local/etc/frr
|
||||||
sudo touch /usr/local/etc/frr/zebra.conf
|
sudo touch /usr/local/etc/frr/zebra.conf
|
||||||
sudo touch /usr/local/etc/frr/bgpd.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 chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||||
sudo chmod 640 /usr/local/etc/frr/*.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
|
# Routing: We need to forward packets
|
||||||
net.inet.ip.forwarding=1
|
net.inet.ip.forwarding=1
|
||||||
net.inet6.ip6.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:
|
FreeBSD 9 restrictions:
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
- MPLS is not supported on `FreeBSD`. MPLS requires a Linux Kernel
|
- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel
|
||||||
(4.5 or higher). LDP can be built, but may have limited use
|
(4.5 or higher). LDP can be built, but may have limited use without
|
||||||
without MPLS
|
MPLS
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages: (Allow the install of the package managment tool if this
|
||||||
(Allow the install of the package managment tool if this is first package
|
is first package install and asked)
|
||||||
install and asked)
|
|
||||||
|
::
|
||||||
|
|
||||||
pkg install -y git autoconf automake libtool gmake gawk \
|
pkg install -y git autoconf automake libtool gmake gawk \
|
||||||
pkgconf texinfo json-c bison flex py27-pytest c-ares \
|
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
|
Make sure there is no /usr/bin/flex preinstalled (and use the newly
|
||||||
installed in /usr/local/bin):
|
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
|
||||||
(FreeBSD frequently provides a older flex as part of the base OS which
|
as part of the base OS which takes preference in path)
|
||||||
takes preference in path)
|
|
||||||
|
::
|
||||||
|
|
||||||
rm -f /usr/bin/flex
|
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 install clang36
|
||||||
pkg delete clang34
|
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
|
**This assumes you want to build and install FRR from source and not
|
||||||
using any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr group and user
|
Add frr group and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pw groupadd frr -g 101
|
pw groupadd frr -g 101
|
||||||
pw groupadd frrvty -g 102
|
pw groupadd frrvty -g 102
|
||||||
@ -49,6 +59,8 @@ using any packages**
|
|||||||
(You may prefer different options on configure statement. These are just
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -71,12 +83,16 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
sudo gmake install
|
sudo gmake install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /usr/local/etc/frr
|
sudo mkdir /usr/local/etc/frr
|
||||||
sudo touch /usr/local/etc/frr/zebra.conf
|
sudo touch /usr/local/etc/frr/zebra.conf
|
||||||
sudo touch /usr/local/etc/frr/bgpd.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 chown frr:frrvty /usr/local/etc/frr/vtysh.conf
|
||||||
sudo chmod 640 /usr/local/etc/frr/*.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
|
# Routing: We need to forward packets
|
||||||
net.inet.ip.forwarding=1
|
net.inet.ip.forwarding=1
|
||||||
net.inet6.ip6.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:
|
NetBSD 6 restrictions:
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
|
- MPLS is not supported on ``NetBSD``. MPLS requires a Linux Kernel
|
||||||
(4.5 or higher). LDP can be built, but may have limited use
|
(4.5 or higher). LDP can be built, but may have limited use without
|
||||||
without MPLS
|
MPLS
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Configure Package location:
|
Configure Package location:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
PKG_PATH="ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
|
PKG_PATH="ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
|
||||||
export PKG_PATH
|
export PKG_PATH
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo pkg_add git autoconf automake libtool gmake gawk openssl \
|
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):
|
Install SSL Root Certificates (for git https access):
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo pkg_add mozilla-rootcerts
|
sudo pkg_add mozilla-rootcerts
|
||||||
sudo touch /etc/openssl/openssl.cnf
|
sudo touch /etc/openssl/openssl.cnf
|
||||||
sudo mozilla-rootcerts install
|
sudo mozilla-rootcerts install
|
||||||
|
|
||||||
Select default Python and py.test
|
Select default Python and py.test
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
|
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
|
sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
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 92 frr
|
||||||
sudo groupadd -g 93 frrvty
|
sudo groupadd -g 93 frrvty
|
||||||
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
||||||
-d /nonexistent -s /sbin/nologin frr
|
-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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -67,12 +83,16 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
sudo gmake install
|
sudo gmake install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /var/log/frr
|
sudo mkdir /var/log/frr
|
||||||
sudo mkdir /usr/pkg/etc/frr
|
sudo mkdir /usr/pkg/etc/frr
|
||||||
sudo touch /usr/pkg/etc/frr/zebra.conf
|
sudo touch /usr/pkg/etc/frr/zebra.conf
|
||||||
@ -88,23 +108,35 @@ an example)
|
|||||||
sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
|
sudo chown frr:frrvty /usr/pkg/etc/frr/*.conf
|
||||||
sudo chmod 640 /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
|
# Routing: We need to forward packets
|
||||||
net.inet.ip.forwarding=1
|
net.inet.ip.forwarding=1
|
||||||
net.inet6.ip6.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/
|
cp pkgsrc/*.sh /etc/rc.d/
|
||||||
chmod 555 /etc/rc.d/*.sh
|
chmod 555 /etc/rc.d/*.sh
|
||||||
|
|
||||||
### Enable FRR processes
|
Enable FRR processes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
(Enable the required processes only)
|
(Enable the required processes only)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
echo "zebra=YES" >> /etc/rc.conf
|
echo "zebra=YES" >> /etc/rc.conf
|
||||||
echo "bgpd=YES" >> /etc/rc.conf
|
echo "bgpd=YES" >> /etc/rc.conf
|
||||||
echo "ospfd=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:
|
NetBSD 7 restrictions:
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
- MPLS is not supported on `NetBSD`. MPLS requires a Linux Kernel
|
- MPLS is not supported on ``NetBSD``. MPLS requires a Linux Kernel
|
||||||
(4.5 or higher). LDP can be built, but may have limited use
|
(4.5 or higher). LDP can be built, but may have limited use without
|
||||||
without MPLS
|
MPLS
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo pkgin install git autoconf automake libtool gmake gawk openssl \
|
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):
|
Install SSL Root Certificates (for git https access):
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo pkgin install mozilla-rootcerts
|
sudo pkgin install mozilla-rootcerts
|
||||||
sudo touch /etc/openssl/openssl.cnf
|
sudo touch /etc/openssl/openssl.cnf
|
||||||
sudo mozilla-rootcerts install
|
sudo mozilla-rootcerts install
|
||||||
|
|
||||||
Select default Python and py.test
|
Select default Python and py.test
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python
|
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
|
sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
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 92 frr
|
||||||
sudo groupadd -g 93 frrvty
|
sudo groupadd -g 93 frrvty
|
||||||
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
sudo useradd -g 92 -u 92 -G frrvty -c "FRR suite" \
|
||||||
-d /nonexistent -s /sbin/nologin frr
|
-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
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -61,12 +74,16 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
sudo gmake install
|
sudo gmake install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo mkdir /usr/pkg/etc/frr
|
sudo mkdir /usr/pkg/etc/frr
|
||||||
sudo touch /usr/pkg/etc/frr/zebra.conf
|
sudo touch /usr/pkg/etc/frr/zebra.conf
|
||||||
sudo touch /usr/pkg/etc/frr/bgpd.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 chown frr:frrvty /usr/pkg/etc/frr/*.conf
|
||||||
sudo chmod 640 /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
|
# Routing: We need to forward packets
|
||||||
net.inet.ip.forwarding=1
|
net.inet.ip.forwarding=1
|
||||||
net.inet6.ip6.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/
|
cp pkgsrc/*.sh /etc/rc.d/
|
||||||
chmod 555 /etc/rc.d/*.sh
|
chmod 555 /etc/rc.d/*.sh
|
||||||
|
|
||||||
### Enable FRR processes
|
Enable FRR processes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
(Enable the required processes only)
|
(Enable the required processes only)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
echo "zebra=YES" >> /etc/rc.conf
|
echo "zebra=YES" >> /etc/rc.conf
|
||||||
echo "bgpd=YES" >> /etc/rc.conf
|
echo "bgpd=YES" >> /etc/rc.conf
|
||||||
echo "ospfd=YES" >> /etc/rc.conf
|
echo "ospfd=YES" >> /etc/rc.conf
|
@ -1,23 +1,28 @@
|
|||||||
Building FRR on OmniOS (OpenSolaris) from Git Source
|
OmniOS (OpenSolaris)
|
||||||
====================================================
|
====================================================
|
||||||
|
|
||||||
OmniOS restrictions:
|
OmniOS restrictions:
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
- MPLS is not supported on `OmniOS` or `Solaris`. MPLS requires a Linux
|
- MPLS is not supported on ``OmniOS`` or ``Solaris``. MPLS requires a
|
||||||
Kernel (4.5 or higher). LDP can be built, but may have limited use
|
Linux Kernel (4.5 or higher). LDP can be built, but may have limited
|
||||||
without MPLS
|
use without MPLS
|
||||||
|
|
||||||
### Enable IP & IPv6 forwarding
|
Enable IP & IPv6 forwarding
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
routeadm -e ipv4-forwarding
|
routeadm -e ipv4-forwarding
|
||||||
routeadm -e ipv6-forwarding
|
routeadm -e ipv6-forwarding
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pkg install \
|
pkg install \
|
||||||
developer/build/autoconf \
|
developer/build/autoconf \
|
||||||
developer/build/automake \
|
developer/build/automake \
|
||||||
@ -32,10 +37,12 @@ Add packages:
|
|||||||
library/idnkit/header-idnkit \
|
library/idnkit/header-idnkit \
|
||||||
system/header \
|
system/header \
|
||||||
system/library/math/header-math \
|
system/library/math/header-math \
|
||||||
git libtool gawk pkg-config
|
git libtool gawk pkg-config
|
||||||
|
|
||||||
Add additional Solaris packages:
|
Add additional Solaris packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pkgadd -d http://get.opencsw.org/now
|
pkgadd -d http://get.opencsw.org/now
|
||||||
/opt/csw/bin/pkgutil -U
|
/opt/csw/bin/pkgutil -U
|
||||||
/opt/csw/bin/pkgutil -y -i texinfo
|
/opt/csw/bin/pkgutil -y -i texinfo
|
||||||
@ -45,33 +52,50 @@ Add additional Solaris packages:
|
|||||||
|
|
||||||
Add libjson to Solaris equivalent of ld.so.conf
|
Add libjson to Solaris equivalent of ld.so.conf
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
crle -l /opt/csw/lib -u
|
crle -l /opt/csw/lib -u
|
||||||
|
|
||||||
Add pytest:
|
Add pytest:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pip install pytest
|
pip install pytest
|
||||||
|
|
||||||
|
Install Sphinx:::
|
||||||
|
|
||||||
|
pip install sphinx
|
||||||
|
|
||||||
Select Python 2.7 as default (required for pytest)
|
Select Python 2.7 as default (required for pytest)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
rm -f /usr/bin/python
|
rm -f /usr/bin/python
|
||||||
ln -s /opt/csw/bin/python2.7 /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`
|
Fix PATH for all users and non-interactive sessions. Edit
|
||||||
and add the following default PATH:
|
``/etc/default/login`` and add the following default PATH:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin:/opt/csw/bin
|
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
|
PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin:/opt/csw/bin
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr group and user
|
Add frr group and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 93 frr
|
sudo groupadd -g 93 frr
|
||||||
sudo groupadd -g 94 frrvty
|
sudo groupadd -g 94 frrvty
|
||||||
@ -81,6 +105,8 @@ any packages**
|
|||||||
(You may prefer different options on configure statement. These are just
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -106,12 +132,15 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
sudo gmake install
|
sudo gmake install
|
||||||
|
|
||||||
### Enable IP & IPv6 forwarding
|
Enable IP & IPv6 forwarding
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
routeadm -e ipv4-forwarding
|
routeadm -e ipv4-forwarding
|
||||||
routeadm -e ipv6-forwarding
|
routeadm -e ipv6-forwarding
|
@ -1,39 +1,52 @@
|
|||||||
Building FRR on OpenBSD 6 from Git Source
|
OpenBSD 6
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Configure PKG_PATH
|
Configure PKG\_PATH
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
export PKG_PATH=http://ftp5.usa.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(machine -a)/
|
export PKG_PATH=http://ftp5.usa.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(machine -a)/
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pkg_add git autoconf-2.69p2 automake-1.15p0 libtool bison
|
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)
|
Select Python2.7 as default (required for pytest)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
ln -s /usr/local/bin/python2.7 /usr/local/bin/python
|
ln -s /usr/local/bin/python2.7 /usr/local/bin/python
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr group and user
|
Add frr group and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
groupadd -g 525 _frr
|
groupadd -g 525 _frr
|
||||||
groupadd -g 526 _frrvty
|
groupadd -g 526 _frrvty
|
||||||
useradd -g 525 -u 525 -c "FRR suite" -G _frrvty \
|
useradd -g 525 -u 525 -c "FRR suite" -G _frrvty \
|
||||||
-d /nonexistent -s /sbin/nologin _frr
|
-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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example)
|
an example)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
export AUTOCONF_VERSION="2.69"
|
export AUTOCONF_VERSION="2.69"
|
||||||
@ -56,12 +69,15 @@ an example)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
gmake
|
gmake
|
||||||
gmake check
|
gmake check
|
||||||
doas gmake install
|
doas gmake install
|
||||||
|
|
||||||
### Create empty FRR configuration files
|
Create empty FRR configuration files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
doas mkdir /var/frr
|
doas mkdir /var/frr
|
||||||
doas chown _frr:_frr /var/frr
|
doas chown _frr:_frr /var/frr
|
||||||
@ -83,47 +99,65 @@ an example)
|
|||||||
doas chmod 750 /etc/frr
|
doas chmod 750 /etc/frr
|
||||||
doas chmod 640 /etc/frr/*.conf
|
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.forwarding=1 # 1=Permit forwarding of IPv6 packets
|
||||||
net.inet6.ip6.mforwarding=1 # 1=Permit forwarding of IPv6 multicast packets
|
net.inet6.ip6.mforwarding=1 # 1=Permit forwarding of IPv6 multicast packets
|
||||||
net.inet6.ip6.multipath=1 # 1=Enable IPv6 multipath routing
|
net.inet6.ip6.multipath=1 # 1=Enable IPv6 multipath routing
|
||||||
|
|
||||||
**Reboot** to apply the config to the system
|
**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
|
doas ifconfig em0 mpls
|
||||||
|
|
||||||
Alternatively, to make MPLS forwarding persistent across reboots, add the "mpls"
|
Alternatively, to make MPLS forwarding persistent across reboots, add
|
||||||
keyword in the hostname.* files of the desired interfaces. Example:
|
the "mpls" keyword in the hostname.\* files of the desired interfaces.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
cat /etc/hostname.em0
|
cat /etc/hostname.em0
|
||||||
inet 10.0.1.1 255.255.255.0 mpls
|
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
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(create them in /etc/rc.d - no example are included at this time with
|
||||||
FRR source)
|
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
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# $OpenBSD: frr_zebra.rc,v 1.1 2013/04/18 20:29:08 sthen Exp $
|
# $OpenBSD: frr_zebra.rc,v 1.1 2013/04/18 20:29:08 sthen Exp $
|
||||||
|
|
||||||
daemon="/usr/local/sbin/zebra -d"
|
daemon="/usr/local/sbin/zebra -d"
|
||||||
|
|
||||||
. /etc/rc.d/rc.subr
|
. /etc/rc.d/rc.subr
|
||||||
|
|
||||||
rc_cmd $1
|
rc_cmd $1
|
||||||
|
|
||||||
### Enable FRR processes
|
Enable FRR processes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
(Enable the required processes only)
|
(Enable the required processes only)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
echo "frr_zebra=YES" >> /etc/rc.conf
|
echo "frr_zebra=YES" >> /etc/rc.conf
|
||||||
echo "frr_bgpd=YES" >> /etc/rc.conf
|
echo "frr_bgpd=YES" >> /etc/rc.conf
|
||||||
echo "frr_ospfd=YES" >> /etc/rc.conf
|
echo "frr_ospfd=YES" >> /etc/rc.conf
|
@ -1,40 +1,46 @@
|
|||||||
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
|
- MPLS is not supported on ``Ubuntu 12.04`` with default kernel. MPLS
|
||||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||||
without MPLS)
|
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||||
For an updated Ubuntu Kernel, see http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
||||||
texinfo libpam0g-dev dejagnu libjson0-dev pkg-config libpam0g-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
|
Install newer bison from 14.04 package source (Ubuntu 12.04 package
|
||||||
is too old)
|
source is too old)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
mkdir builddir
|
mkdir builddir
|
||||||
cd builddir
|
cd builddir
|
||||||
wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.dsc
|
wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.dsc
|
||||||
wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg.orig.tar.bz2
|
wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg.orig.tar.bz2
|
||||||
wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.debian.tar.gz
|
wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.debian.tar.gz
|
||||||
tar -jxvf bison_3.0.2.dfsg.orig.tar.bz2
|
tar -jxvf bison_3.0.2.dfsg.orig.tar.bz2
|
||||||
cd bison-3.0.2.dfsg/
|
cd bison-3.0.2.dfsg/
|
||||||
tar xzf ../bison_3.0.2.dfsg-2.debian.tar.gz
|
tar xzf ../bison_3.0.2.dfsg-2.debian.tar.gz
|
||||||
sudo apt-get build-dep bison
|
sudo apt-get build-dep bison
|
||||||
debuild -b -uc -us
|
debuild -b -uc -us
|
||||||
cd ..
|
cd ..
|
||||||
sudo dpkg -i ./libbison-dev_3.0.2.dfsg-2_amd64.deb ./bison_3.0.2.dfsg-2_amd64.deb
|
sudo dpkg -i ./libbison-dev_3.0.2.dfsg-2_amd64.deb ./bison_3.0.2.dfsg-2_amd64.deb
|
||||||
cd ..
|
cd ..
|
||||||
rm -rf builddir
|
rm -rf builddir
|
||||||
|
|
||||||
Install newer version of autoconf and automake:
|
Install newer version of autoconf and automake:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
|
wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
|
||||||
tar xvf autoconf-2.69.tar.gz
|
tar xvf autoconf-2.69.tar.gz
|
||||||
cd autoconf-2.69
|
cd autoconf-2.69
|
||||||
@ -42,7 +48,7 @@ Install newer version of autoconf and automake:
|
|||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
|
wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz
|
||||||
tar xvf automake-1.15.tar.gz
|
tar xvf automake-1.15.tar.gz
|
||||||
cd automake-1.15
|
cd automake-1.15
|
||||||
@ -53,15 +59,20 @@ Install newer version of autoconf and automake:
|
|||||||
|
|
||||||
Install pytest:
|
Install pytest:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
pip install pytest
|
pip install pytest
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 92 frr
|
sudo groupadd -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvty
|
sudo groupadd -r -g 85 frrvty
|
||||||
@ -69,10 +80,14 @@ any packages**
|
|||||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||||
sudo usermod -a -G frrvty frr
|
sudo usermod -a -G frrvty frr
|
||||||
|
|
||||||
### Download Source, configure and compile it
|
Download Source, configure and compile it
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
(You may prefer different options on configure statement. These are just
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -95,12 +110,15 @@ an example.)
|
|||||||
--enable-rtadv \
|
--enable-rtadv \
|
||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
sudo make install
|
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/log/frr
|
||||||
sudo install -m 775 -o frr -g frrvty -d /etc/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 frr /dev/null /etc/frr/nhrpd.conf
|
||||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.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)
|
other settings)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Uncomment the next line to enable packet forwarding for IPv4
|
# Uncomment the next line to enable packet forwarding for IPv4
|
||||||
net.ipv4.ip_forward=1
|
net.ipv4.ip_forward=1
|
||||||
|
|
||||||
@ -129,27 +150,38 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
**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 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 /etc/frr/daemons
|
||||||
sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
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
|
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.
|
|
||||||
|
|
||||||
zebra=yes
|
Enable daemons
|
||||||
bgpd=yes
|
~~~~~~~~~~~~~~
|
||||||
ospfd=yes
|
|
||||||
ospf6d=yes
|
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||||
ripd=yes
|
those daemons you want to start by systemd.
|
||||||
ripngd=yes
|
| For example.
|
||||||
isisd=yes
|
|
||||||
|
::
|
||||||
### Start the init.d service
|
|
||||||
- /etc/init.d/frr start
|
zebra=yes
|
||||||
- use `/etc/init.d/frr status` to check its status.
|
bgpd=yes
|
||||||
|
ospfd=yes
|
||||||
|
ospf6d=yes
|
||||||
|
ripd=yes
|
||||||
|
ripngd=yes
|
||||||
|
isisd=yes
|
||||||
|
|
||||||
|
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
|
- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
|
||||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||||
without MPLS)
|
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||||
For an updated Ubuntu Kernel, see http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
||||||
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
|
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)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 92 frr
|
sudo groupadd -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvty
|
sudo groupadd -r -g 85 frrvty
|
||||||
@ -29,10 +34,14 @@ any packages**
|
|||||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||||
sudo usermod -a -G frrvty frr
|
sudo usermod -a -G frrvty frr
|
||||||
|
|
||||||
### Download Source, configure and compile it
|
Download Source, configure and compile it
|
||||||
(You may prefer different options on configure statement. These are just
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -56,12 +65,15 @@ an example.)
|
|||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--enable-ldpd \
|
--enable-ldpd \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
sudo make install
|
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/log/frr
|
||||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||||
@ -74,14 +86,17 @@ an example.)
|
|||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
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)
|
other settings)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Uncomment the next line to enable packet forwarding for IPv4
|
# Uncomment the next line to enable packet forwarding for IPv4
|
||||||
net.ipv4.ip_forward=1
|
net.ipv4.ip_forward=1
|
||||||
|
|
||||||
@ -90,30 +105,35 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
**Reboot** or use `sysctl -p` to apply the same config to the running system
|
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
||||||
### Install the init.d service
|
system ### Install the init.d service
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo install -m 755 tools/frr /etc/init.d/frr
|
sudo install -m 755 tools/frr /etc/init.d/frr
|
||||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
||||||
sudo install -m 644 tools/etc/frr/daemons.conf /etc/frr/daemons.conf
|
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
|
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.
|
Enable daemons
|
||||||
For example.
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
zebra=yes
|
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||||
bgpd=yes
|
those daemons you want to start by systemd.
|
||||||
ospfd=yes
|
| For example.
|
||||||
ospf6d=yes
|
|
||||||
ripd=yes
|
::
|
||||||
ripngd=yes
|
|
||||||
isisd=yes
|
zebra=yes
|
||||||
|
bgpd=yes
|
||||||
### Start the init.d service
|
ospfd=yes
|
||||||
- /etc/init.d/frr start
|
ospf6d=yes
|
||||||
- use `/etc/init.d/frr status` to check its status.
|
ripd=yes
|
||||||
|
ripngd=yes
|
||||||
|
isisd=yes
|
||||||
|
|
||||||
|
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
|
- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
|
||||||
Linux Kernel 4.5 or higher (LDP can be built, but may have limited use
|
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
||||||
without MPLS)
|
limited use without MPLS) For an updated Ubuntu Kernel, see
|
||||||
For an updated Ubuntu Kernel, see
|
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
||||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
|
||||||
|
|
||||||
Install required packages
|
Install required packages
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Add packages:
|
Add packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
apt-get install git autoconf automake libtool make gawk libreadline-dev \
|
||||||
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
|
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)
|
Get FRR, compile it and install it (from Git)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not using
|
**This assumes you want to build and install FRR from source and not
|
||||||
any packages**
|
using any packages**
|
||||||
|
|
||||||
### Add frr groups and user
|
Add frr groups and user
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
sudo groupadd -g 92 frr
|
sudo groupadd -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvty
|
sudo groupadd -r -g 85 frrvty
|
||||||
@ -30,10 +35,14 @@ any packages**
|
|||||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||||
sudo usermod -a -G frrvty frr
|
sudo usermod -a -G frrvty frr
|
||||||
|
|
||||||
### Download Source, configure and compile it
|
Download Source, configure and compile it
|
||||||
(You may prefer different options on configure statement. These are just
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
(You may prefer different options on configure statement. These are just
|
||||||
an example.)
|
an example.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
git clone https://github.com/frrouting/frr.git frr
|
||||||
cd frr
|
cd frr
|
||||||
./bootstrap.sh
|
./bootstrap.sh
|
||||||
@ -57,12 +66,15 @@ an example.)
|
|||||||
--enable-fpm \
|
--enable-fpm \
|
||||||
--enable-systemd=yes \
|
--enable-systemd=yes \
|
||||||
--with-pkg-git-version \
|
--with-pkg-git-version \
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
--with-pkg-extra-version=-MyOwnFRRVersion
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
sudo make install
|
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/log/frr
|
||||||
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
sudo install -m 775 -o frr -g frrvty -d /etc/frr
|
||||||
@ -75,14 +87,17 @@ an example.)
|
|||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
|
||||||
sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
|
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)
|
other settings)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Uncomment the next line to enable packet forwarding for IPv4
|
# Uncomment the next line to enable packet forwarding for IPv4
|
||||||
net.ipv4.ip_forward=1
|
net.ipv4.ip_forward=1
|
||||||
|
|
||||||
@ -91,10 +106,14 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
### Enable MPLS Forwarding (with Linux Kernel >= 4.5)
|
Enable MPLS Forwarding (with Linux Kernel >= 4.5)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Edit `/etc/sysctl.conf` and the following lines. Make sure to add a line
|
Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
|
||||||
equal to `net.mpls.conf.eth0.input` or each interface used with MPLS
|
line equal to ``net.mpls.conf.eth0.input`` or each interface used with
|
||||||
|
MPLS
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
# Enable MPLS Label processing on all interfaces
|
# Enable MPLS Label processing on all interfaces
|
||||||
net.mpls.conf.eth0.input=1
|
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.conf.eth2.input=1
|
||||||
net.mpls.platform_labels=100000
|
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
|
# Load MPLS Kernel Modules
|
||||||
mpls-router
|
mpls-router
|
||||||
mpls-iptunnel
|
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/frr.service /etc/systemd/system/frr.service
|
||||||
sudo install -m 644 tools/etc/default/frr /etc/default/frr
|
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 tools/etc/frr/frr.conf /etc/frr/frr.conf
|
||||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
sudo 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.
|
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
||||||
For example.
|
those daemons you want to start by systemd.
|
||||||
|
| For example.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
zebra=yes
|
zebra=yes
|
||||||
bgpd=yes
|
bgpd=yes
|
||||||
@ -135,9 +164,13 @@ For example.
|
|||||||
ripngd=yes
|
ripngd=yes
|
||||||
isisd=yes
|
isisd=yes
|
||||||
|
|
||||||
### Enable the systemd service
|
Enable the systemd service
|
||||||
- systemctl enable frr
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
### Start the systemd service
|
- systemctl enable frr
|
||||||
- systemctl start frr
|
|
||||||
- use `systemctl status frr` to check its status.
|
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 ------------------------------------------------
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# 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
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
@ -36,7 +39,7 @@ templates_path = ['_templates']
|
|||||||
|
|
||||||
# The suffix(es) of source filenames.
|
# The suffix(es) of source filenames.
|
||||||
# You can specify multiple suffix as a list of string:
|
# You can specify multiple suffix as a list of string:
|
||||||
# source_suffix = ['.rst', '.md']
|
# source_suffix = ['.rst']
|
||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
@ -59,14 +62,51 @@ version = u'?.?'
|
|||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = u'?.?-?'
|
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\["([^"]+)"\]="(.*)"$')
|
val = re.compile('^S\["([^"]+)"\]="(.*)"$')
|
||||||
with open('../../config.status', 'r') as cfgstatus:
|
with open('../../config.status', 'r') as cfgstatus:
|
||||||
for ln in cfgstatus.readlines():
|
for ln in cfgstatus.readlines():
|
||||||
m = val.match(ln)
|
m = val.match(ln)
|
||||||
if m is None: continue
|
if not m or m.group(1) not in replace_vars.keys(): continue
|
||||||
if m.group(1) == 'PACKAGE_VERSION':
|
replace_vars[m.group(1)] = m.group(2)
|
||||||
release = m.group(2)
|
|
||||||
version = release.split('-')[0]
|
# 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
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# 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
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# 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
|
# 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
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
#html_theme_options = {}
|
html_theme_options = {
|
||||||
|
'sidebarbgcolor': '#374249'
|
||||||
|
}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
#html_theme_path = []
|
#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
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
# of the sidebar.
|
# 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
|
# 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
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
# pixels large.
|
# 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,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# 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
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
# .htaccess) here, relative to this directory. These files are copied
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
@ -231,13 +273,13 @@ latex_elements = {
|
|||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
(master_doc, 'FRR.tex', u'FRR Documentation',
|
(master_doc, 'FRR.tex', u"FRR Developer's Manual",
|
||||||
u'FRR', 'manual'),
|
u'FRR', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
# the title page.
|
# 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,
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
# not chapters.
|
# not chapters.
|
||||||
@ -261,7 +303,7 @@ latex_documents = [
|
|||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
(master_doc, 'frr', u'FRR Documentation',
|
(master_doc, 'frr', u"FRR Developer's Manual",
|
||||||
[author], 1)
|
[author], 1)
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -275,7 +317,7 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
(master_doc, 'FRR', u'FRR Documentation',
|
(master_doc, 'frr', u"FRR Developer's Manual",
|
||||||
author, 'FRR', 'One line description of project.',
|
author, 'FRR', 'One line description of project.',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
@ -291,3 +333,9 @@ texinfo_documents = [
|
|||||||
|
|
||||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||||
#texinfo_no_detailmenu = False
|
#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!
|
Welcome to FRR's documentation!
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
Contents:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
workflow
|
||||||
library
|
library
|
||||||
|
bgpd
|
||||||
|
building
|
||||||
Indices and tables
|
ospf-api
|
||||||
==================
|
ospf-sr
|
||||||
|
|
||||||
* :ref:`genindex`
|
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
|
||||||
|
|
@ -6,5 +6,7 @@ libfrr library facilities
|
|||||||
|
|
||||||
memtypes
|
memtypes
|
||||||
hooks
|
hooks
|
||||||
|
cli
|
||||||
|
modules
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ Definition
|
|||||||
>80% of cases.
|
>80% of cases.
|
||||||
|
|
||||||
.. todo::
|
.. todo::
|
||||||
|
|
||||||
Daemons currently have ``daemon_memory.[ch]`` files listing all of
|
Daemons currently have ``daemon_memory.[ch]`` files listing all of
|
||||||
their MTYPEs. This is not how it should be, most of these types
|
their MTYPEs. This is not how it should be, most of these types
|
||||||
should be moved into the appropriate files where they are used.
|
should be moved into the appropriate files where they are used.
|
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
|
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
|
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
|
Implementation details
|
||||||
----------------------
|
----------------------
|
||||||
@ -196,17 +196,17 @@ yourself:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
modprobe mpls_router
|
modprobe mpls_router
|
||||||
modprobe mpls_gso
|
modprobe mpls_gso
|
||||||
modprobe mpls_iptunnel
|
modprobe mpls_iptunnel
|
||||||
|
|
||||||
Then, you must activate MPLS on the interface you would used:
|
Then, you must activate MPLS on the interface you would used:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
sysctl -w net.mpls.conf.enp0s9.input=1
|
sysctl -w net.mpls.conf.enp0s9.input=1
|
||||||
sysctl -w net.mpls.conf.lo.input=1
|
sysctl -w net.mpls.conf.lo.input=1
|
||||||
sysctl -w net.mpls.platform_labels=1048575
|
sysctl -w net.mpls.platform_labels=1048575
|
||||||
|
|
||||||
The last line fix the maximum MPLS label value.
|
The last line fix the maximum MPLS label value.
|
||||||
|
|
||||||
@ -215,8 +215,8 @@ enable with:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
ip -M route
|
ip -M route
|
||||||
ip route
|
ip route
|
||||||
|
|
||||||
The first command show the MPLS LFIB table while the second show the FIB
|
The first command show the MPLS LFIB table while the second show the FIB
|
||||||
table which contains route with MPLS label encapsulation.
|
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
|
systcl -w net.ipv4.conf.all.rp_filter=0
|
||||||
sysctl -w net.ipv4.conf.lo.rp_filter=0
|
sysctl -w net.ipv4.conf.lo.rp_filter=0
|
||||||
|
|
||||||
OSPFd
|
OSPFd
|
||||||
~~~~~
|
~~~~~
|
||||||
@ -240,16 +240,16 @@ Routing.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
router ospf
|
router ospf
|
||||||
ospf router-id 192.168.1.11
|
ospf router-id 192.168.1.11
|
||||||
capability opaque
|
capability opaque
|
||||||
mpls-te on
|
mpls-te on
|
||||||
mpls-te router-address 192.168.1.11
|
mpls-te router-address 192.168.1.11
|
||||||
router-info area 0.0.0.0
|
router-info area 0.0.0.0
|
||||||
segment-routing on
|
segment-routing on
|
||||||
segment-routing global-block 10000 19999
|
segment-routing global-block 10000 19999
|
||||||
segment-routing node-msd 8
|
segment-routing node-msd 8
|
||||||
segment-routing prefix 192.168.1.11/32 index 1100
|
segment-routing prefix 192.168.1.11/32 index 1100
|
||||||
|
|
||||||
The first segment-routing statement enable it. The Second one set the SRGB,
|
The first segment-routing statement enable it. The Second one set the SRGB,
|
||||||
third line the MSD and finally, set the Prefix SID index for a given prefix.
|
third line the MSD and finally, set the Prefix SID index for a given prefix.
|
||||||
@ -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
|
project 5GEx (Grant Agreement no. 671636), which is partially funded
|
||||||
by the European Commission.
|
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 |