AM_CPPFLAGS += -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/lib \
-I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib
-VERSION_TYPE := $(shell if echo $(VERSION) | grep -q '^[0-9\.]*$$'; then echo RELEASE ; else echo DEV ; fi)
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) -DVERSION_TYPE_$(VERSION_TYPE)
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE)
LIBCAP = @LIBCAP@
EXTRA_DIST =
}
}
-static inline int is_evpn_prefix_default(struct prefix *evp)
+static inline int is_evpn_prefix_default(const struct prefix *evp)
{
if (evp->family != AF_EVPN)
return 0;
afi_t afi, safi_t safi, enum bgp_show_type type);
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi);
+ safi_t safi, uint8_t use_json);
static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|prefix-list WORD\
|filter-list WORD\
|statistics\
- |community <AA:NN|local-AS|no-advertise|no-export|graceful-shutdown> [exact-match]\
|community-list <(1-500)|WORD> [exact-match]\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
"Display routes conforming to the filter-list\n"
"Regular expression access list name\n"
"BGP RIB advertisement statistics\n"
- "Display routes matching the communities\n"
- COMMUNITY_AANN_STR
- "Do not send outside local AS (well-known community)\n"
- "Do not advertise to any peer (well-known community)\n"
- "Do not export to next AS (well-known community)\n"
- "Graceful shutdown (well-known community)\n"
- "Exact match of the communities\n"
"Display routes matching the community-list\n"
"community-list number\n"
"community-list name\n"
int exact_match = 0;
struct bgp *bgp = NULL;
int idx = 0;
- int idx_community_type = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp);
return bgp_show_route_map(vty, bgp, argv[idx + 1]->arg, afi,
safi, bgp_show_type_route_map);
- if (argv_find(argv, argc, "community", &idx)) {
- /* show a specific community */
- if (argv_find(argv, argc, "local-AS", &idx_community_type)
- || argv_find(argv, argc, "no-advertise",
- &idx_community_type)
- || argv_find(argv, argc, "no-export", &idx_community_type)
- || argv_find(argv, argc, "graceful-shutdown",
- &idx_community_type)
- || argv_find(argv, argc, "AA:NN", &idx_community_type)) {
-
- if (argv_find(argv, argc, "exact-match", &idx))
- exact_match = 1;
- return bgp_show_community(vty, bgp,
- argv[idx_community_type]->arg,
- exact_match, afi, safi);
- }
- }
-
if (argv_find(argv, argc, "community-list", &idx)) {
const char *clist_number_or_name = argv[++idx]->arg;
if (++idx < argc && strmatch(argv[idx]->text, "exact-match"))
[<\
cidr-only\
|dampening <flap-statistics|dampened-paths>\
- |community \
+ |community [<AA:NN|local-AS|no-advertise|no-export|graceful-shutdown>] [exact-match]\
>] [json]",
SHOW_STR
IP_STR
"Display flap statistics of routes\n"
"Display paths suppressed due to dampening\n"
"Display routes matching the communities\n"
+ COMMUNITY_AANN_STR
+ "Do not send outside local AS (well-known community)\n"
+ "Do not advertise to any peer (well-known community)\n"
+ "Do not export to next AS (well-known community)\n"
+ "Graceful shutdown (well-known community)\n"
+ "Exact match of the communities\n"
JSON_STR)
{
afi_t afi = AFI_IP6;
enum bgp_show_type sh_type = bgp_show_type_normal;
struct bgp *bgp = NULL;
int idx = 0;
+ int idx_community_type = 0;
+ int exact_match = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp);
}
if (argv_find(argv, argc, "community", &idx)) {
- /* show all communities */
- return bgp_show(vty, bgp, afi, safi,
- bgp_show_type_community_all, NULL, uj);
+
+ /* show a specific community */
+ if (argv_find(argv, argc, "local-AS", &idx_community_type) ||
+ argv_find(argv, argc, "no-advertise",
+ &idx_community_type) ||
+ argv_find(argv, argc, "no-export",
+ &idx_community_type) ||
+ argv_find(argv, argc, "graceful-shutdown",
+ &idx_community_type) ||
+ argv_find(argv, argc, "AA:NN", &idx_community_type)) {
+ if (argv_find(argv, argc, "exact-match", &idx))
+ exact_match = 1;
+
+ return (bgp_show_community(vty, bgp,
+ argv[idx_community_type]->arg,
+ exact_match, afi, safi, uj));
+ } else {
+
+ /* show all communities */
+ return (bgp_show(vty, bgp, afi, safi,
+ bgp_show_type_community_all, NULL,
+ uj));
+ }
}
+
return bgp_show(vty, bgp, afi, safi, sh_type, NULL, uj);
}
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi)
+ safi_t safi, uint8_t use_json)
{
struct community *com;
int ret = 0;
ret = bgp_show(vty, bgp, afi, safi,
(exact ? bgp_show_type_community_exact
: bgp_show_type_community),
- com, 0);
+ com, use_json);
community_free(com);
return ret;
/* Compares the peer specified in the 'match peer' clause with the peer
received in bgp_info->peer. If it is the same, or if the peer structure
received is a peer_group containing it, returns RMAP_MATCH. */
-static route_map_result_t route_match_peer(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_peer(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_ip_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_ip_next_hop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_ip_route_source(void *rule,
- struct prefix *prefix,
+ const struct prefix *pfx,
route_map_object_t type,
void *object)
{
struct peer *peer;
struct prefix_ipv4 p;
- if (type == RMAP_BGP && prefix->family == AF_INET) {
+ if (type == RMAP_BGP && pfx->family == AF_INET) {
bgp_info = object;
peer = bgp_info->peer;
/* `match ip address prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* `match ip next-hop prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* `match ip route-source prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_route_source_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_route_source_prefix_list(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* 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,
+ const struct prefix *p,
route_map_object_t
type, void *object)
{
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_mac_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_vni(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_vni(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
vni_t vni = 0;
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_evpn_route_type(void *rule,
- struct prefix *prefix,
+ const struct prefix *pfx,
route_map_object_t type,
void *object)
{
if (type == RMAP_BGP) {
route_type = *((uint8_t *)rule);
- if (route_type == prefix->u.prefix_evpn.route_type)
+ if (route_type == pfx->u.prefix_evpn.route_type)
return RMAP_MATCH;
}
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_local_pref(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match as-path ASPATH' */
/* Match function for as-path match. I assume given object is */
-static route_map_result_t route_match_aspath(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_aspath(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function for community match. */
static route_map_result_t route_match_community(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function for lcommunity match. */
static route_map_result_t route_match_lcommunity(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function for extcommunity match. */
static route_map_result_t route_match_ecommunity(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
and `address-family vpnv4'. */
/* `match origin' */
-static route_map_result_t route_match_origin(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_origin(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* match probability { */
static route_map_result_t route_match_probability(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_interface(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set ip next-hop IP_ADDRESS' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
};
static route_map_result_t route_set_ip_nexthop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Set local preference. */
static route_map_result_t route_set_local_pref(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set weight WEIGHT' */
/* Set weight. */
-static route_map_result_t route_set_weight(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_weight(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* For AS path prepend mechanism. */
static route_map_result_t route_set_aspath_prepend(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
* Make a deep copy of existing AS_PATH, but for the first ASn only.
*/
static route_map_result_t route_set_aspath_exclude(void *rule,
- struct prefix *dummy,
+ const struct prefix *dummy,
route_map_object_t type,
void *object)
{
};
/* For community set mechanism. */
-static route_map_result_t route_set_community(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_community(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* For lcommunity set mechanism. */
static route_map_result_t route_set_lcommunity(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* For large community set mechanism. */
static route_map_result_t route_set_lcommunity_delete(void *rule,
- struct prefix *prefix,
+ const struct prefix *pfx,
route_map_object_t type,
void *object)
{
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
/* For community set mechanism. */
-static route_map_result_t route_set_community_delete(void *rule,
- struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static route_map_result_t route_set_community_delete(
+ void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct community_list *list;
struct community *merge;
/* For community set mechanism. Used by _rt and _soo. */
static route_map_result_t route_set_ecommunity(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set origin ORIGIN' */
/* For origin set. */
-static route_map_result_t route_set_origin(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_origin(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* For atomic aggregate set. */
static route_map_result_t route_set_atomic_aggregate(void *rule,
- struct prefix *prefix,
+ const struct prefix *pfx,
route_map_object_t type,
void *object)
{
};
static route_map_result_t route_set_aggregator_as(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
};
/* Set tag to object. object must be pointer to struct bgp_info */
-static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_tag(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
/* Set label-index to object. object must be pointer to struct bgp_info */
static route_map_result_t route_set_label_index(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ipv6 address IP_ACCESS_LIST' */
static route_map_result_t route_match_ipv6_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ipv6 next-hop IP_ADDRESS' */
static route_map_result_t route_match_ipv6_next_hop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ipv6 address prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* Set nexthop to object. ojbect must be pointer to struct attr. */
static route_map_result_t route_set_ipv6_nexthop_global(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
/* Set next-hop preference value. */
static route_map_result_t
-route_set_ipv6_nexthop_prefer_global(void *rule, struct prefix *prefix,
+route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct bgp_info *bgp_info;
/* Set nexthop to object. ojbect must be pointer to struct attr. */
static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
/* Set nexthop to object. ojbect must be pointer to struct attr. */
static route_map_result_t route_set_ipv6_nexthop_peer(void *rule,
- struct prefix *prefix,
+ const struct prefix *pfx,
route_map_object_t type,
void *object)
{
/* `set ipv4 vpn next-hop A.B.C.D' */
static route_map_result_t route_set_vpnv4_nexthop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set ipv6 vpn next-hop A.B.C.D' */
static route_map_result_t route_set_vpnv6_nexthop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* For origin set. */
static route_map_result_t route_set_originator_id(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
#endif
/* BGP global configuration. */
-#if defined(VERSION_TYPE_DEV) && (CONFDATE > 20190601)
+#if (CONFDATE > 20190601)
CPP_NOTICE("bgpd: time to remove deprecated bgp multiple-instance")
CPP_NOTICE("This includes BGP_OPT_MULTIPLE_INSTANCE")
#endif
return CMD_SUCCESS;
}
-#if defined(VERSION_TYPE_DEV) && (CONFDATE > 20190601)
+#if (CONFDATE > 20190601)
CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco")
CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG")
#endif
}
/* "bgp enforce-first-as" configuration. */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180517
+#if CONFDATE > 20180517
CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands")
#endif
json_object_string_add(
json_neigh, "remoteRouterId",
inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1)));
+ json_object_string_add(
+ json_neigh, "localRouterId",
+ inet_ntop(AF_INET, &bgp->router_id, buf1,
+ sizeof(buf1)));
/* Confederation */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
uptime -= p->uptime;
epoch_tbuf = time(NULL) - uptime;
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20200101
+#if CONFDATE > 20200101
CPP_NOTICE(
"bgpTimerUp should be deprecated and can be removed now");
#endif
}
/* clang-format off */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180517
+#if CONFDATE > 20180517
CPP_NOTICE("bgpd: remove 'bgp enforce-first-as' config migration from bgp_config_write")
#endif
/* clang-format on */
dnl ----------
dnl configure date
dnl ----------
-CONFDATE=`date '+%Y%m%d'`
+dev_version=`echo $VERSION | grep dev`
+#don't expire deprecated code in non 'dev' branch
+if test "${dev_version}" = ""; then
+ CONFDATE=0
+else
+ CONFDATE=`date '+%Y%m%d'`
+fi
AC_SUBST(CONFDATE)
dnl ------------------------------
developer/workflow.rst \
developer/zebra.rst \
user/babeld.rst \
+ user/ldpd.rst \
user/basic.rst \
user/bgp.rst \
user/bugs.rst \
There's also the ``frr_module`` symbol in modules, pretty much a
standard entry point for loadable modules.
+Command line parameters
+-----------------------
+
+Command line parameters can be passed directly to a module by appending a
+colon to the module name when loading it, e.g. ``-M mymodule:myparameter``.
+The text after the colon will be accessible in the module's code through
+``THIS_MODULE->load_args``. For example, see how the format parameter is
+configured in the ``zfpm_init()`` function inside ``zebra_fpm.c``.
+
Hooks
-----
.. code-block:: c
- #if defined(VERSION_TYPE_DEV) && CONFDATE > 20180403
+ #if CONFDATE > 20180403
CPP_NOTICE("Use of <XYZ> is deprecated, please use <ABC>")
#endif
isis
isisd
lan
+ldpd
le
libc
libcap
zebra
bgp
babeld
+ ldpd
eigrpd
isisd
nhrpd
--- /dev/null
+.. _ldp:
+
+***
+LDP
+***
+
+The *ldpd* daemon is a standardised protocol that permits exchanging MPLS label
+information between MPLS devices. The LDP protocol creates peering between
+devices, so as to exchange that label information. This information is stored in
+MPLS table of *zebra*, and it injects that MPLS information in the underlying
+system (Linux kernel or OpenBSD system for instance).
+*ldpd* provides necessary options to create a Layer 2 VPN across MPLS network.
+For instance, it is possible to interconnect several sites that share the same
+broadcast domain.
+
+FRR implements LDP as described in :rfc:`5036`; other LDP standard are the
+following ones: :rfc:`6720`, :rfc:`6667`, :rfc:`5919`, :rfc:`5561`, :rfc:`7552`,
+:rfc:`4447`.
+Because MPLS is already available, FRR also supports :rfc:`3031`.
+
+Running Ldpd
+============
+
+The *ldpd* daemon can be invoked with any of the common
+options (:ref:`common-invocation-options`).
+
+The *zebra* daemon must be running before *ldpd* is invoked.
+
+Configuration of *ldpd* is done in its configuration file
+:file:`ldpd.conf`.
+
+
+.. _understanding-ldp:
+
+Understanding LDP principles
+============================
+
+Let's first introduce some definitions that permit understand better the LDP
+protocol:
+
+- `LSR` : Labeled Switch Router. Networking devices handling labels used to
+ forward traffic between and through them.
+
+- `LER` : Labeled Edge Router. A Labeled edge router is located at the edge of
+ an MPLS network, generally between an IP network and an MPLS network.
+
+
+``LDP`` aims at sharing label information across devices. It tries to establish
+peering with remote LDP capable devices, first by discovering using UDP port 646
+, then by peering using TCP port 646. Once the TCP session is established, the
+label information is shared, through label advertisements.
+
+There are different methods to send label advertisement modes. The
+implementation actually supports the following : Liberal Label Retention +
+Downstream Unsolicited + Independent Control.
+The other advertising modes are depicted below, and compared with the current
+implementation.
+
+- Liberal label retention versus conservative mode
+ In liberal mode, every label sent by every LSR is stored in the MPLS table.
+ In conservative mode, only the label that was sent by the best next hop
+ (determined by the IGP metric) for that particular FEC is stored in the MPLS
+ table.
+
+- Independent LSP Control versus ordered LSP Control
+ MPLS has two ways of binding labels to FEC’s; either through ordered LSP
+ control, or independent LSP control.
+ Ordered LSP control only binds a label to a FEC if it is the egress LSR, or
+ the router received a label binding for a FEC from the next hop router. In
+ this mode, an MPLS router will create a label binding for each FEC and
+ distribute it to its neighbors so long as he has a entry in the RIB for the
+ destination.
+ In the other mode, label bindings are made without any dependencies on another
+ router advertising a label for a particular FEC. Each router makes it own
+ independent decision to create a label for each FEC.
+ By default IOS uses Independent LSP Control, while Juniper implements the
+ Ordered Control. Both modes are interoperable, the difference is that Ordered
+ Control prevent blackholing during the LDP convergence process, at cost of
+ slowing down the convergence itself
+
+- unsolicited downstream versus downstream on demand
+ Downstream on demand label distribution is where an LSR must explicitly
+ request that a label be sent from its downstream router for a particular FEC.
+ Unsolicited label distribution is where a label is sent from the downstream
+ router without the original router requesting it.
+
+.. _configuring-ldpd:
+
+.. _ldp-configuration:
+
+LDP Configuration
+===================
+
+.. index:: [no] mpls ldp
+.. clicmd:: [no] mpls ldp
+
+ Enable or disable LDP daemon
+
+.. index:: [no] router-id A.B.C.D
+.. clicmd:: [no] router-id A.B.C.D
+
+ The following command located under MPLS router node configures the MPLS
+ router-id of the local device.
+
+.. index:: [no] address-family [ipv4 | ipv6]
+.. clicmd:: [no] address-family [ipv4 | ipv6]
+
+ Configure LDP for IPv4 or IPv6 address-family. Located under MPLS route node,
+ this subnode permits configuring the LDP neighbors.
+
+.. index:: [no] interface IFACE
+.. clicmd:: [no] interface IFACE
+
+ Located under MPLS address-family node, use this command to enable or disable
+ LDP discovery per interface. IFACE stands for the interface name where LDP is
+ enabled. By default it is disabled. Once this command executed, the
+ address-family interface node is configured.
+
+.. index:: [no] discovery transport-address A.B.C.D | A:B::C:D
+.. clicmd:: [no] discovery transport-address A.B.C.D | A:B::C:D
+
+ Located under mpls address-family interface node, use this command to set
+ the IPv4 or IPv6 transport-address used by the LDP protocol to talk on this
+ interface.
+
+.. index:: [no] neighbor A.B.C.D password PASSWORD
+.. clicmd:: [no] neighbor A.B.C.D password PASSWORD
+
+ The following command located under MPLS router node configures the router
+ of a LDP device. This device, if found, will have to comply with the
+ configured password. PASSWORD is a clear text password wit its digest sent
+ through the network.
+
+.. index:: [no] neighbor A.B.C.D holdtime HOLDTIME
+.. clicmd:: [no] neighbor A.B.C.D holdtime HOLDTIME
+
+ The following command located under MPLS router node configures the holdtime
+ value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive
+ mechanism. That value can be configured between 15 and 65535 seconds. After
+ this time of non response, the LDP established session will be considered as
+ set to down. By default, no holdtime is configured for the LDP devices.
+
+.. index:: [no] discovery hello holdtime HOLDTIME
+.. clicmd:: [no] discovery hello holdtime HOLDTIME
+
+.. index:: [no] discovery hello interval INTERVAL
+.. clicmd:: [no] discovery hello interval INTERVAL
+
+ INTERVAL value ranges from 1 to 65535 seconds. Default value is 5 seconds.
+ This is the value between each hello timer message sent.
+ HOLDTIME value ranges from 1 to 65535 seconds. Default value is 15 seconds.
+ That value is added as a TLV in the LDP messages.
+
+.. _show-ldp-information:
+
+Show LDP Information
+====================
+
+These commands dump various parts of *ldpd*.
+
+.. index:: show mpls ldp neighbor [A.B.C.D]
+.. clicmd:: show mpls ldp neighbor [A.B.C.D]
+
+ This command dumps the various neighbors discovered. Below example shows that
+ local machine has an operation neighbor with ID set to 1.1.1.1.
+
+ ::
+
+ west-vm# show mpls ldp neighbor
+ AF ID State Remote Address Uptime
+ ipv4 1.1.1.1 OPERATIONAL 1.1.1.1 00:01:37
+ west-vm#
+
+.. index:: show mpls ldp neighbor [A.B.C.D] capabilities
+.. clicmd:: show mpls ldp neighbor [A.B.C.D] capabilities
+
+.. index:: show mpls ldp neighbor [A.B.C.D] detail
+.. clicmd:: show mpls ldp neighbor [A.B.C.D] detail
+
+ Above commands dump other neighbor information.
+
+.. index:: show mpls ldp discovery [detail]
+.. clicmd:: show mpls ldp discovery [detail]
+
+.. index:: show mpls ldp ipv4 discovery [detail]
+.. clicmd:: show mpls ldp ipv4 discovery [detail]
+
+.. index:: show mpls ldp ipv6 discovery [detail]
+.. clicmd:: show mpls ldp ipv6 discovery [detail]
+
+ Above commands dump discovery information.
+
+.. index:: show mpls ldp ipv4 interface
+.. clicmd:: show mpls ldp ipv4 interface
+
+.. index:: show mpls ldp ipv6 interface
+.. clicmd:: show mpls ldp ipv6 interface
+
+ Above command dumps the IPv4 or IPv6 interface per where LDP is enabled.
+ Below output illustrates what is dumped for IPv4.
+
+ ::
+
+ west-vm# show mpls ldp ipv4 interface
+ AF Interface State Uptime Hello Timers ac
+ ipv4 eth1 ACTIVE 00:08:35 5/15 0
+ ipv4 eth3 ACTIVE 00:08:35 5/15 1
+
+
+.. index:: show mpls ldp ipv4|ipv6 binding
+.. clicmd:: show mpls ldp ipv4|ipv6 binding
+
+ Above command dumps the binding obtained through MPLS exchanges with LDP.
+
+ ::
+
+ west-vm# show mpls ldp ipv4 binding
+ AF Destination Nexthop Local Label Remote Label In Use
+ ipv4 1.1.1.1/32 1.1.1.1 16 imp-null yes
+ ipv4 2.2.2.2/32 1.1.1.1 imp-null 16 no
+ ipv4 10.0.2.0/24 1.1.1.1 imp-null imp-null no
+ ipv4 10.115.0.0/24 1.1.1.1 imp-null 17 no
+ ipv4 10.135.0.0/24 1.1.1.1 imp-null imp-null no
+ ipv4 10.200.0.0/24 1.1.1.1 17 imp-null yes
+ west-vm#
+
+LDP debugging commands
+========================
+
+.. index::
+ simple: debug mpls ldp KIND
+ simple: no debug mpls ldp KIND
+
+.. clicmd:: [no] debug mpls ldp KIND
+
+ Enable or disable debugging messages of a given kind. ``KIND`` can
+ be one of:
+
+ - ``discovery``
+ - ``errors``
+ - ``event``
+ - ``labels``
+ - ``messages``
+ - ``zebra``
+
+LDP Example Configuration
+=========================
+
+Below configuration gives a typical MPLS configuration of a device located in a
+MPLS backbone. LDP is enabled on two interfaces and will attempt to peer with
+two neighbors with router-id set to either 1.1.1.1 or 3.3.3.3.
+
+.. code-block:: frr
+
+ mpls ldp
+ router-id 2.2.2.2
+ neighbor 1.1.1.1 password test
+ neighbor 3.3.3.3 password test
+ !
+ address-family ipv4
+ discovery transport-address 2.2.2.2
+ !
+ interface eth1
+ !
+ interface eth3
+ !
+ exit-address-family
+ !
+
+
+Deploying LDP across a backbone generally is done in a full mesh configuration
+topology. LDP is typically deployed with an IGP like OSPF, that helps discover
+the remote IPs. Below example is an OSPF configuration extract that goes with
+LDP configuration
+
+.. code-block:: frr
+
+ router ospf
+ ospf router-id 2.2.2.2
+ network 0.0.0.0/0 area 0
+ !
+
+
+Below output shows the routing entry on the LER side. The OSPF routing entry
+(10.200.0.0) is associated with Label entry (17), and shows that MPLS push action
+that traffic to that destination will be applied.
+
+::
+
+ north-vm# show ip route
+ Codes: K - kernel route, C - connected, S - static, R - RIP,
+ O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
+ T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
+ F - PBR,
+ > - selected route, * - FIB route
+
+ O>* 1.1.1.1/32 [110/120] via 10.115.0.1, eth2, label 16, 00:00:15
+ O>* 2.2.2.2/32 [110/20] via 10.115.0.1, eth2, label implicit-null, 00:00:15
+ O 3.3.3.3/32 [110/10] via 0.0.0.0, loopback1 onlink, 00:01:19
+ C>* 3.3.3.3/32 is directly connected, loopback1, 00:01:29
+ O>* 10.0.2.0/24 [110/11] via 10.115.0.1, eth2, label implicit-null, 00:00:15
+ O 10.100.0.0/24 [110/10] is directly connected, eth1, 00:00:32
+ C>* 10.100.0.0/24 is directly connected, eth1, 00:00:32
+ O 10.115.0.0/24 [110/10] is directly connected, eth2, 00:00:25
+ C>* 10.115.0.0/24 is directly connected, eth2, 00:00:32
+ O>* 10.135.0.0/24 [110/110] via 10.115.0.1, eth2, label implicit-null, 00:00:15
+ O>* 10.200.0.0/24 [110/210] via 10.115.0.1, eth2, label 17, 00:00:15
+ north-vm#
+
thread_add_timer(master, isis_run_dr_l2, circuit,
2 * circuit->hello_interval[1],
&circuit->u.bc.t_run_dr[1]);
- } else {
+ } else if (circuit->circ_type == CIRCUIT_T_P2P) {
/* initializing the hello send threads
* for a ptp IF
*/
void isis_circuit_down(struct isis_circuit *circuit)
{
- if (circuit->state != C_STATE_UP)
- return;
-
/* Clear the flags for all the lsps of the circuit. */
isis_circuit_update_all_srmflags(circuit, 0);
}
/* send one gratuitous hello to spead up convergence */
- if (circuit->is_type & IS_LEVEL_1)
- send_hello(circuit, IS_LEVEL_1);
- if (circuit->is_type & IS_LEVEL_2)
- send_hello(circuit, IS_LEVEL_2);
+ if (circuit->state == C_STATE_UP) {
+ if (circuit->is_type & IS_LEVEL_1)
+ send_hello(circuit, IS_LEVEL_1);
+ if (circuit->is_type & IS_LEVEL_2)
+ send_hello(circuit, IS_LEVEL_2);
+ }
circuit->upadjcount[0] = 0;
circuit->upadjcount[1] = 0;
#include "isis_routemap.h"
static route_map_result_t route_match_ip_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* ------------------------------------------------------------*/
static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* ------------------------------------------------------------*/
static route_map_result_t route_match_ipv6_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* ------------------------------------------------------------*/
static route_map_result_t
-route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* ------------------------------------------------------------*/
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
install_element(LDP_IPV6_NODE, &ldp_label_remote_accept_cmd);
install_element(LDP_IPV6_NODE, &ldp_ttl_security_disable_cmd);
install_element(LDP_IPV6_NODE, &ldp_interface_cmd);
+ install_element(LDP_IPV6_NODE, &no_ldp_interface_cmd);
install_element(LDP_IPV6_NODE, &ldp_session_holdtime_cmd);
install_element(LDP_IPV6_NODE, &ldp_neighbor_ipv6_targeted_cmd);
install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd);
#else
#define CPP_WARN(text)
+#define CPP_NOTICE(text)
#endif
#endif /* _FRR_COMPILER_H */
}
/* If filter match to the prefix then return 1. */
-static int filter_match_cisco(struct filter *mfilter, struct prefix *p)
+static int filter_match_cisco(struct filter *mfilter, const struct prefix *p)
{
struct filter_cisco *filter;
struct in_addr mask;
}
/* If filter match to the prefix then return 1. */
-static int filter_match_zebra(struct filter *mfilter, struct prefix *p)
+static int filter_match_zebra(struct filter *mfilter, const struct prefix *p)
{
struct filter_zebra *filter = NULL;
}
/* Apply access list to object (which should be struct prefix *). */
-enum filter_type access_list_apply(struct access_list *access, void *object)
+enum filter_type access_list_apply(struct access_list *access,
+ const void *object)
{
struct filter *filter;
- struct prefix *p = (struct prefix *)object;
+ const struct prefix *p = (const struct prefix *)object;
if (access == NULL)
return FILTER_DENY;
access->remark = NULL;
}
- if (access->head == NULL && access->tail == NULL
- && access->remark == NULL)
+ if (access->head == NULL && access->tail == NULL)
access_list_delete(access);
return CMD_SUCCESS;
extern void access_list_add_hook(void (*func)(struct access_list *));
extern void access_list_delete_hook(void (*func)(struct access_list *));
extern struct access_list *access_list_lookup(afi_t, const char *);
-extern enum filter_type access_list_apply(struct access_list *, void *);
+extern enum filter_type access_list_apply(struct access_list *access,
+ const void *object);
#endif /* _ZEBRA_FILTER_H */
* and remove list_delete_original and the list_delete #define
* Additionally remove list_free entirely
*/
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181001
+#if CONFDATE > 20181001
CPP_NOTICE("list_delete without double pointer is deprecated, please fixup")
#endif
*args++ = '\0';
if (!strchr(name, '/')) {
- if (!handle && execname) {
+ if (execname) {
snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir,
execname, name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
}
static int prefix_list_entry_match(struct prefix_list_entry *pentry,
- struct prefix *p)
+ const struct prefix *p)
{
int ret;
return 1;
}
-enum prefix_list_type prefix_list_apply_which_prefix(struct prefix_list *plist,
- struct prefix **which,
- void *object)
+enum prefix_list_type prefix_list_apply_which_prefix(
+ struct prefix_list *plist,
+ const struct prefix **which,
+ const void *object)
{
struct prefix_list_entry *pentry, *pbest = NULL;
- struct prefix *p = (struct prefix *)object;
- uint8_t *byte = p->u.val;
+ const struct prefix *p = (const struct prefix *)object;
+ const uint8_t *byte = p->u.val;
size_t depth;
size_t validbits = p->prefixlen;
struct pltrie_table *table;
* If it is a empty plist return a NULL pointer.
*/
extern enum prefix_list_type
-prefix_list_apply_which_prefix(struct prefix_list *plist, struct prefix **which,
- void *object);
+prefix_list_apply_which_prefix(struct prefix_list *plist,
+ const struct prefix **which,
+ const void *object);
#define prefix_list_apply(A, B) prefix_list_apply_which_prefix((A), NULL, (B))
extern struct prefix_list *prefix_bgp_orf_lookup(afi_t, const char *);
static route_map_result_t
route_map_apply_match(struct route_map_rule_list *match_list,
- struct prefix *prefix, route_map_object_t type,
+ const struct prefix *prefix, route_map_object_t type,
void *object)
{
route_map_result_t ret = RMAP_NOMATCH;
}
/* Apply route map to the object. */
-route_map_result_t route_map_apply(struct route_map *map, struct prefix *prefix,
+route_map_result_t route_map_apply(struct route_map *map,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
static int recursion = 0;
const char *str;
/* Function for value set or match. */
- route_map_result_t (*func_apply)(void *, struct prefix *,
- route_map_object_t, void *);
+ route_map_result_t (*func_apply)(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object);
/* Compile argument and return result as void *. */
void *(*func_compile)(const char *);
/* Apply route map to the object. */
extern route_map_result_t route_map_apply(struct route_map *map,
- struct prefix *,
+ const struct prefix *prefix,
route_map_object_t object_type,
void *object);
#define STREAM_CONCAT_REMAIN(S1, S2, size) ((size) - (S1)->endp - (S2)->endp)
/* deprecated macros - do not use in new code */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181128
+#if CONFDATE > 20181128
CPP_NOTICE("lib: time to remove deprecated stream.h macros")
#endif
#define STREAM_PNT(S) stream_pnt((S))
}
if (vrf->ns_ctxt != NULL) {
ns = (struct ns *)vrf->ns_ctxt;
- if (ns && 0 != strcmp(ns->name, pathname)) {
+ if (!strcmp(ns->name, pathname)) {
if (vty)
vty_out(vty,
"VRF %u already configured with NETNS %s\n",
ns->vrf_ctxt = (void *)vrf;
vrf->ns_ctxt = (void *)ns;
/* update VRF netns NAME */
- if (vrf)
- strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
+ strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
if (!ns_enable(ns, vrf_update_vrf_id)) {
if (vty)
* The usage of work_queue_free is being transitioned to pass
* in the double pointer to remove use after free's.
*/
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20190205
+#if CONFDATE > 20190205
CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup")
#endif
extern void work_queue_free_and_null(struct work_queue **);
extern struct zclient *zclient_new(struct thread_master *);
/* clang-format off */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20181101
+#if CONFDATE > 20181101
CPP_NOTICE("zclient_new_notify can take over or zclient_new now");
#endif
/* clang-format on */
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
/* clang-format off */
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180823
+#if CONFDATE > 20180823
CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
#endif
/* clang-format on */
/* Routemap Functions */
static route_map_result_t
-ospf6_routemap_rule_match_address_prefixlist(void *rule, struct prefix *prefix,
+ospf6_routemap_rule_match_address_prefixlist(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t
-ospf6_routemap_rule_match_interface(void *rule, struct prefix *prefix,
+ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct interface *ifp;
/* Match function for matching route tags */
static route_map_result_t ospf6_routemap_rule_match_tag(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
};
static route_map_result_t
-ospf6_routemap_rule_set_metric_type(void *rule, struct prefix *prefix,
+ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
char *metric_type = rule;
};
static route_map_result_t
-ospf6_routemap_rule_set_metric(void *rule, struct prefix *prefix,
+ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
char *metric = rule;
};
static route_map_result_t
-ospf6_routemap_rule_set_forwarding(void *rule, struct prefix *prefix,
+ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
char *forwarding = rule;
};
static route_map_result_t ospf6_routemap_rule_set_tag(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
return CMD_SUCCESS;
}
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180828
+#if CONFDATE > 20180828
CPP_NOTICE("ospf6: `router-id A.B.C.D` deprecated 2017/08/28")
#endif
ALIAS_HIDDEN(ospf6_router_id, ospf6_router_id_hdn_cmd, "router-id A.B.C.D",
"Configure OSPF6 Router-ID\n" V4NOTATION_STR)
-#if defined(VERSION_TYPE_DEV) && CONFDATE > 20180828
+#if CONFDATE > 20180828
CPP_NOTICE("ospf6: `no router-id A.B.C.D` deprecated 2017/08/28")
#endif
ALIAS_HIDDEN(no_ospf6_router_id, no_ospf6_router_id_hdn_cmd,
/* `match ip netxthop ' */
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_ip_nexthop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ip next-hop prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_ip_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ip address prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_interface(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
route_match_interface_free};
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set metric-type TYPE' */
/* Set metric-type to attribute. */
static route_map_result_t route_set_metric_type(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
route_set_metric_type_free,
};
-static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
"Source/RP address\n"
"Multicast Group address\n")
{
- struct pim_nexthop_cache pnc;
+ struct pim_nexthop_cache *pnc = NULL;
struct prefix nht_p;
int result = 0;
struct in_addr src_addr, grp_addr;
char grp_str[PREFIX_STRLEN];
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct pim_rpf rpf;
if (!vrf)
return CMD_WARNING;
grp_addr))
return CMD_SUCCESS;
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
nht_p.u.prefix4 = vif_source;
grp.u.prefix4 = grp_addr;
memset(&nexthop, 0, sizeof(nexthop));
- if (pim_find_or_track_nexthop(vrf->info, &nht_p, NULL, NULL, &pnc))
- result = pim_ecmp_nexthop_search(vrf->info, &pnc, &nexthop,
+ memset(&rpf, 0, sizeof(struct pim_rpf));
+ rpf.rpf_addr.family = AF_INET;
+ rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
+ rpf.rpf_addr.u.prefix4 = vif_source;
+
+ pnc = pim_nexthop_cache_find(vrf->info, &rpf);
+ if (pnc)
+ result = pim_ecmp_nexthop_search(vrf->info, pnc, &nexthop,
&nht_p, &grp, 0);
else
- result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop,
- vif_source, &nht_p, &grp, 0);
+ result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop, &nht_p,
+ &grp, 0);
if (!result) {
vty_out(vty,
mask = PIM_OIF_FLAG_PROTO_IGMP;
/* SGRpt entry could have empty oil */
- if (ch->upstream->channel_oil)
- pim_channel_del_oif(ch->upstream->channel_oil,
- ch->interface, mask);
+ pim_channel_del_oif(ch->upstream->channel_oil, ch->interface,
+ mask);
/*
* Do we have any S,G's that are inheriting?
* Nuke from on high too.
socklen_t fromlen = sizeof(from);
socklen_t tolen = sizeof(to);
ifindex_t ifindex = -1;
- int cont = 1;
int len;
- while (cont) {
+ while (1) {
len = pim_socket_recvfromto(igmp->fd, buf, sizeof(buf), &from,
&fromlen, &to, &tolen, &ifindex);
if (len < 0) {
struct pim_nexthop *nexthop, struct prefix *src,
struct prefix *grp, int neighbor_needed)
{
- struct pim_neighbor *nbr = NULL;
+ struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr;
+ struct interface *ifps[MULTIPATH_NUM];
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
struct interface *ifp = NULL;
uint32_t hash_val = 0, mod_val = 0;
uint8_t nh_iter = 0, found = 0;
+ uint32_t i, num_nbrs = 0;
if (!pnc || !pnc->nexthop_num || !nexthop)
return 0;
}
}
}
+
+ /*
+ * Look up all interfaces and neighbors,
+ * store for later usage
+ */
+ for (nh_node = pnc->nexthop, i = 0; nh_node;
+ nh_node = nh_node->next, i++) {
+ ifps[i] = if_lookup_by_index(nh_node->ifindex, pim->vrf_id);
+ if (ifps[i]) {
+ nbrs[i] = pim_neighbor_find(ifps[i],
+ nh_node->gate.ipv4);
+ if (nbrs[i] || pim_if_connected_to_source(ifps[i],
+
+ src->u.prefix4))
+ num_nbrs++;
+ }
+ }
if (pim->ecmp_enable) {
+ uint32_t consider = pnc->nexthop_num;
+
+ if (neighbor_needed && num_nbrs < consider)
+ consider = num_nbrs;
+
+ if (consider == 0)
+ return 0;
+
// PIM ECMP flag is enable then choose ECMP path.
hash_val = pim_compute_ecmp_hash(src, grp);
- mod_val = hash_val % pnc->nexthop_num;
+ mod_val = hash_val % consider;
}
for (nh_node = pnc->nexthop; nh_node && (found == 0);
nh_node = nh_node->next) {
first_ifindex = nh_node->ifindex;
- ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ ifp = ifps[nh_iter];
if (!ifp) {
if (PIM_DEBUG_PIM_NHT) {
char addr_str[INET_ADDRSTRLEN];
if (neighbor_needed
&& !pim_if_connected_to_source(ifp, src->u.prefix4)) {
- nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
+ nbr = nbrs[nh_iter];
if (!nbr && !if_is_loopback(ifp)) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
}
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct in_addr addr,
- struct prefix *src, struct prefix *grp,
- int neighbor_needed)
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed)
{
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
- struct pim_neighbor *nbr = NULL;
+ struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL;
int num_ifindex;
- struct interface *ifp;
+ struct interface *ifps[MULTIPATH_NUM], *ifp;
int first_ifindex;
int found = 0;
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
+ uint32_t num_nbrs = 0;
+ char addr_str[PREFIX_STRLEN];
if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
+ sizeof(addr_str));
zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
__PRETTY_FUNCTION__, addr_str, pim->vrf->name,
nexthop->last_lookup_time);
memset(nexthop_tab, 0,
sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
- num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
- addr, PIM_NEXTHOP_LOOKUP_MAX);
+ num_ifindex =
+ zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+ src->u.prefix4, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_warn(
"%s: could not find nexthop ifindex for address %s(%s)",
__PRETTY_FUNCTION__, addr_str, pim->vrf->name);
- }
return 0;
}
+ /*
+ * Look up all interfaces and neighbors,
+ * store for later usage
+ */
+ for (i = 0; i < num_ifindex; i++) {
+ ifps[i] = if_lookup_by_index(nexthop_tab[i].ifindex,
+ pim->vrf_id);
+ if (ifps[i]) {
+ nbrs[i] = pim_neighbor_find(
+ ifps[i], nexthop_tab[i].nexthop_addr.u.prefix4);
+ if (nbrs[i]
+ || pim_if_connected_to_source(ifps[i],
+ src->u.prefix4))
+ num_nbrs++;
+ }
+ }
+
// If PIM ECMP enable then choose ECMP path.
if (pim->ecmp_enable) {
+ uint32_t consider = num_ifindex;
+
+ if (neighbor_needed && num_nbrs < consider)
+ consider = num_nbrs;
+
+ if (consider == 0)
+ return 0;
+
hash_val = pim_compute_ecmp_hash(src, grp);
- mod_val = hash_val % num_ifindex;
+ mod_val = hash_val % consider;
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: hash_val %u mod_val %u",
__PRETTY_FUNCTION__, hash_val, mod_val);
}
+ i = 0;
while (!found && (i < num_ifindex)) {
first_ifindex = nexthop_tab[i].ifindex;
- ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ ifp = ifps[i];
if (!ifp) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s %s: could not find interface for ifindex %d (address %s(%s))",
__FILE__, __PRETTY_FUNCTION__,
first_ifindex, addr_str,
pim->vrf->name);
- }
if (i == mod_val)
mod_val++;
i++;
}
if (!ifp->info) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
__PRETTY_FUNCTION__, ifp->name,
pim->vrf->name, first_ifindex,
addr_str);
- }
if (i == mod_val)
mod_val++;
i++;
continue;
}
- if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) {
- nbr = pim_neighbor_find(
- ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
+ if (neighbor_needed
+ && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
+ nbr = nbrs[i];
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("ifp name: %s(%s), pim nbr: %p",
ifp->name, pim->vrf->name, nbr);
if (i == mod_val)
mod_val++;
i++;
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr,
- addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: NBR not found on input interface %s(%s) (RPF for source %s)",
__PRETTY_FUNCTION__, ifp->name,
pim->vrf->name, addr_str);
- }
continue;
}
}
if (i == mod_val) {
if (PIM_DEBUG_PIM_NHT) {
char nexthop_str[PREFIX_STRLEN];
- char addr_str[INET_ADDRSTRLEN];
+
pim_addr_dump("<nexthop?>",
&nexthop_tab[i].nexthop_addr,
nexthop_str, sizeof(nexthop_str));
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
zlog_debug(
"%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
__PRETTY_FUNCTION__, nexthop_str,
nexthop_tab[i].protocol_distance;
nexthop->mrib_route_metric =
nexthop_tab[i].route_metric;
- nexthop->last_lookup = addr;
+ nexthop->last_lookup = src->u.prefix4;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
found = 1;
}
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
- struct in_addr addr, struct prefix *src,
- struct prefix *grp)
+ struct prefix *src, struct prefix *grp)
{
- struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
- int num_ifindex;
+ struct pim_nexthop nhop;
int vif_index;
- ifindex_t first_ifindex;
- uint32_t hash_val = 0, mod_val = 0;
+ ifindex_t ifindex;
+ char addr_str[PREFIX_STRLEN];
- memset(nexthop_tab, 0,
- sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
- num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
- addr, PIM_NEXTHOP_LOOKUP_MAX);
- if (num_ifindex < 1) {
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
+ if (PIM_DEBUG_PIM_NHT)
+ pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
+ sizeof(addr_str));
+ if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 0)) {
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: could not find nexthop ifindex for address %s(%s)",
__PRETTY_FUNCTION__, addr_str, pim->vrf->name);
- }
return -1;
}
- // If PIM ECMP enable then choose ECMP path.
- if (pim->ecmp_enable) {
- hash_val = pim_compute_ecmp_hash(src, grp);
- mod_val = hash_val % num_ifindex;
- if (PIM_DEBUG_PIM_NHT_DETAIL)
- zlog_debug("%s: hash_val %u mod_val %u",
- __PRETTY_FUNCTION__, hash_val, mod_val);
- }
-
- first_ifindex = nexthop_tab[mod_val].ifindex;
-
- if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
+ ifindex = nhop.interface->ifindex;
+ if (PIM_DEBUG_PIM_NHT)
zlog_debug(
"%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
- __PRETTY_FUNCTION__, first_ifindex,
- ifindex2ifname(first_ifindex, pim->vrf_id),
+ __PRETTY_FUNCTION__, ifindex,
+ ifindex2ifname(ifindex, pim->vrf_id),
pim->vrf->name, addr_str);
- }
- vif_index = pim_if_find_vifindex_by_ifindex(pim, first_ifindex);
+ vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
if (vif_index < 0) {
if (PIM_DEBUG_PIM_NHT) {
- char addr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<addr?>", addr, addr_str,
- sizeof(addr_str));
zlog_debug(
"%s: low vif_index=%d(%s) < 1 nexthop for address %s",
__PRETTY_FUNCTION__, vif_index, pim->vrf->name,
struct pim_nexthop *nexthop, struct prefix *src,
struct prefix *grp, int neighbor_needed);
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct in_addr addr,
- struct prefix *src, struct prefix *grp,
- int neighbor_needed);
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed);
void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
struct pim_nexthop_cache *pnc, int command);
void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p);
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
- struct in_addr addr, struct prefix *src,
- struct prefix *grp);
+ struct prefix *src, struct prefix *grp);
#endif
*/
static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
struct in_addr rp,
- struct prefix *group)
+ const struct prefix *group)
{
struct listnode *node;
struct rp_info *rp_info;
* Given a group, return the rp_info for that group
*/
static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
- struct prefix *group)
+ const struct prefix *group)
{
struct listnode *node;
struct rp_info *best = NULL;
struct rp_info *rp_info;
struct prefix_list *plist;
- struct prefix *p, *bp;
+ const struct prefix *p, *bp;
struct route_node *rn;
bp = NULL;
&rp_all->group, 1))
return PIM_RP_NO_PATH;
} else {
- if (pim_nexthop_lookup(
+ if (!pim_ecmp_nexthop_lookup(
pim, &rp_all->rp.source_nexthop,
- rp_all->rp.rpf_addr.u.prefix4, 1)
- != 0)
+ &nht_p, &rp_all->group, 1))
return PIM_RP_NO_PATH;
}
pim_rp_check_interfaces(pim, rp_all);
&nht_p, &rp_info->group, 1))
return PIM_RP_NO_PATH;
} else {
- if (pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1)
- != 0)
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1))
return PIM_RP_NO_PATH;
}
"%s: NHT Local Nexthop not found for RP %s ",
__PRETTY_FUNCTION__, buf);
}
- if (pim_nexthop_lookup(
- pim, &rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1) < 0)
+ if (!pim_ecmp_nexthop_lookup(pim,
+ &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1))
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
"Unable to lookup nexthop for rp specified");
__PRETTY_FUNCTION__, buf, buf1);
}
pim_rpf_set_refresh_time(pim);
- pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1);
+ pim_ecmp_nexthop_lookup(pim,
+ &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
}
return (&rp_info->rp);
}
struct prefix nht_p;
struct pim_nexthop_cache pnc;
struct prefix src, grp;
+ bool neigh_needed = true;
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = up->sg.grp;
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
+
+ if ((up->sg.src.s_addr == INADDR_ANY && I_am_RP(pim, up->sg.grp)) ||
+ PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
+ neigh_needed = FALSE;
if (pim_find_or_track_nexthop(pim, &nht_p, up, NULL, &pnc)) {
if (pnc.nexthop_num) {
- if (!pim_ecmp_nexthop_search(
- pim, &pnc, &up->rpf.source_nexthop, &src,
- &grp,
- !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
- && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
- up->flags)))
+ if (!pim_ecmp_nexthop_search(pim, &pnc,
+ &up->rpf.source_nexthop,
+ &src, &grp, neigh_needed))
return PIM_RPF_FAILURE;
}
} else {
- if (!pim_ecmp_nexthop_lookup(
- pim, &rpf->source_nexthop, up->upstream_addr, &src,
- &grp,
- !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
- && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
- up->flags)))
+ if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src,
+ &grp, neigh_needed))
return PIM_RPF_FAILURE;
}
__PRETTY_FUNCTION__, source_str, group_str);
}
input_iface_vif_index = pim_ecmp_fib_lookup_if_vif_index(
- c_oil->pim, vif_source, &src, &grp);
+ c_oil->pim, &src, &grp);
}
if (input_iface_vif_index < 1) {
void igmp_source_forward_start(struct pim_instance *pim,
struct igmp_source *source)
{
+ struct pim_interface *pim_oif;
struct igmp_group *group;
struct prefix_sg sg;
int result;
}
group = source->source_group;
+ pim_oif = group->group_igmp_sock->interface->info;
+ if (!pim_oif) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s: multicast not enabled on oif=%s ?",
+ __PRETTY_FUNCTION__,
+ source->source_group->group_igmp_sock
+ ->interface->name);
+ }
+ return;
+ }
if (!source->source_channel_oil) {
struct in_addr vif_source;
- struct pim_interface *pim_oif;
struct prefix nht_p, src, grp;
struct pim_nexthop_cache out_pnc;
struct pim_nexthop nexthop;
}
} else
input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(
- pim, vif_source, &src, &grp);
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+ &grp);
if (PIM_DEBUG_ZEBRA) {
char buf2[INET_ADDRSTRLEN];
source and receiver attached to the same interface. See TODO
T22.
*/
- pim_oif =
- source->source_group->group_igmp_sock->interface->info;
- if (!pim_oif) {
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug(
- "%s: multicast not enabled on oif=%s ?",
- __PRETTY_FUNCTION__,
- source->source_group->group_igmp_sock
- ->interface->name);
- }
- return;
- }
-
if (input_iface_vif_index == pim_oif->mroute_vif_index) {
/* ignore request for looped MFC entry */
if (PIM_DEBUG_IGMP_TRACE) {
return;
}
+ if (!(PIM_I_am_DR(pim_oif)))
+ return;
+
/*
Feed IGMPv3-gathered local membership information into PIM
per-interface (S,G) state.
*/
if (!pim_ifchannel_local_membership_add(
- group->group_igmp_sock->interface, &sg)) {
+ group->group_igmp_sock->interface, &sg)) {
if (PIM_DEBUG_MROUTE)
zlog_warn("%s: Failure to add local membership for %s",
__PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ nht_p.u.prefix4 = up->upstream_addr;
grp.family = AF_INET;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = up->sg.grp;
}
} else
input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(
- pim, up->upstream_addr, &src, &grp);
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+ &grp);
if (input_iface_vif_index < 1) {
if (PIM_DEBUG_PIM_TRACE) {
%endif
install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr
+# add rpki module to daemon
+%if %{with_rpki}
+ sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons
+%endif
install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_interface(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_ip_next_hop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ip next-hop prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_ip_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ip address prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_tag(void *rule, const struct prefix *p,
route_map_object_t type, void *object)
{
route_tag_t *tag;
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Set nexthop to object. ojbect must be pointer to struct attr. */
static route_map_result_t route_set_ip_nexthop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_interface(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Set nexthop to object. ojbect must be pointer to struct attr. */
static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_tag(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
self.save_contexts(ctx_keys, current_context_lines)
new_ctx = True
- elif line == "end":
+ elif line in ["end", "exit-vrf"]:
self.save_contexts(ctx_keys, current_context_lines)
log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys)
zns = zebra_ns_lookup(ns_id);
ifa = NLMSG_DATA(h);
- if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6)
+ if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
+ zlog_warn(
+ "Invalid address family: %d received from kernel interface addr change: %d",
+ ifa->ifa_family, h->nlmsg_type);
return 0;
+ }
if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
return 0;
if (tb[IFA_LABEL])
label = (char *)RTA_DATA(tb[IFA_LABEL]);
- if (ifp && label && strcmp(ifp->name, label) == 0)
+ if (label && strcmp(ifp->name, label) == 0)
label = NULL;
/* Register interface address to the interface. */
return 0;
}
+ if (!(ifi->ifi_family == AF_UNSPEC || ifi->ifi_family == AF_BRIDGE
+ || ifi->ifi_family == AF_INET6)) {
+ zlog_warn(
+ "Invalid address family: %d received from kernel link change: %d",
+ ifi->ifi_family, h->nlmsg_type);
+ return 0;
+ }
+
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
if (len < 0) {
zlog_err("%s: Message received from netlink is of a broken size %d %zu",
" -z, --socket Set path of zebra socket\n"
" -e, --ecmp Specify ECMP to use.\n"
" -l, --label_socket Socket to external label manager\n"
- " -k, --keep_kernel Don't delete old routes which installed by zebra.\n"
+ " -k, --keep_kernel Don't delete old routes which were installed by zebra.\n"
" -r, --retain When program terminates, retain added route by zebra.\n"
#ifdef HAVE_NETLINK
- " -n, --vrfwnetns Set VRF with NetNS\n"
+ " -n, --vrfwnetns Use NetNS as VRF backend\n"
" -s, --nl-bufsize Set netlink receive buffer size\n"
" --v6-rr-semantics Use v6 RR semantics\n"
#endif /* HAVE_NETLINK */
#if defined(HANDLE_ZAPI_FUZZING)
- " -c <file> Bypass normal startup use this file for tetsting of zapi"
+ " -c <file> Bypass normal startup and use this file for testing of zapi"
#endif
);
/* For debug purpose. */
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
-#if defined(HANDLE_ZAPI_FUZZING)
- if (fuzzing) {
- zserv_read_file(fuzzing);
- exit(0);
- }
-#endif
-
/* Process the configuration file. Among other configuration
* directives we can meet those installing static routes. Such
* requests will not be executed immediately, but queued in
/* RNH init */
zebra_rnh_init();
+#if defined(HANDLE_ZAPI_FUZZING)
+ if (fuzzing) {
+ zserv_read_file(fuzzing);
+ exit(0);
+ }
+#endif
+
+
frr_run(zebrad.master);
/* Not reached... */
memcpy(&p.u.prefix4, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- src_p.prefixlen =
- 0; // Forces debug below to not display anything
+ if (rtm->rtm_src_len != 0) {
+ char buf[PREFIX_STRLEN];
+ zlog_warn("unsupported IPv4 sourcedest route (dest %s vrf %u)",
+ prefix2str(&p, buf, sizeof(buf)), vrf_id);
+ return 0;
+ }
+
+ /* Force debug below to not display anything for source */
+ src_p.prefixlen = 0;
} else if (rtm->rtm_family == AF_INET6) {
p.family = AF_INET6;
memcpy(&p.u.prefix6, dest, 16);
src_p.prefixlen = rtm->rtm_src_len;
}
- if (rtm->rtm_src_len != 0) {
- char buf[PREFIX_STRLEN];
- zlog_warn(
- "unsupported IPv[4|6] sourcedest route (dest %s vrf %u)",
- prefix2str(&p, buf, sizeof(buf)), vrf_id);
- return 0;
- }
-
/*
* For ZEBRA_ROUTE_KERNEL types:
*
nh.vrf_id = nh_vrf_id;
rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
- NULL, &nh, table, metric, mtu, distance, tag);
+ &src_p, &nh, table, metric, mtu, distance, tag);
} else {
/* This is a multipath route */
if (re->nexthop_num == 0)
XFREE(MTYPE_RE, re);
else
- rib_add_multipath(afi, SAFI_UNICAST, &p, NULL,
- re);
+ rib_add_multipath(afi, SAFI_UNICAST, &p,
+ &src_p, re);
}
} else {
if (!tb[RTA_MULTIPATH]) {
if (gate)
memcpy(&nh.gate, gate, sz);
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
- &p, NULL, &nh, table, metric, true);
+ &p, &src_p, &nh, table, metric, true);
} else {
/* XXX: need to compare the entire list of nexthops
* here for NLM_F_APPEND stupidity */
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
- &p, NULL, NULL, table, metric, true);
+ &p, &src_p, NULL, table, metric, true);
}
}
return 0;
}
+ if (!(rtm->rtm_family == AF_INET || rtm->rtm_family == AF_INET6
+ || rtm->rtm_family == AF_ETHERNET
+ || rtm->rtm_family == AF_MPLS)) {
+ zlog_warn(
+ "Invalid address family: %d received from kernel route change: %d",
+ rtm->rtm_family, h->nlmsg_type);
+ return 0;
+ }
+
/* Connected route. */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s %s %s proto %s NS %u",
if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6)
return netlink_ipneigh_change(h, len, ns_id);
+ else {
+ zlog_warn(
+ "Invalid address family: %d received from kernel neighbor change: %d",
+ ndm->ndm_family, h->nlmsg_type);
+ return 0;
+ }
return 0;
}
#endif
/* Interface between zebra message and rtm message. */
-static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re)
+static int kernel_rtm_ipv4(int cmd, const struct prefix *p,
+ struct route_entry *re)
{
struct sockaddr_in *mask = NULL;
#endif /* SIN6_LEN */
/* Interface between zebra message and rtm message. */
-static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re)
+static int kernel_rtm_ipv6(int cmd, const struct prefix *p,
+ struct route_entry *re)
{
struct sockaddr_in6 *mask;
struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
return 0; /*XXX*/
}
-static int kernel_rtm(int cmd, struct prefix *p, struct route_entry *re)
+static int kernel_rtm(int cmd, const struct prefix *p, struct route_entry *re)
{
switch (PREFIX_FAMILY(p)) {
case AF_INET:
}
frh = NLMSG_DATA(h);
- if (frh->family != AF_INET && frh->family != AF_INET6)
+ if (frh->family != AF_INET && frh->family != AF_INET6) {
+ zlog_warn(
+ "Invalid address family: %d received from kernel rule change: %d",
+ frh->family, h->nlmsg_type);
return 0;
+ }
if (frh->action != FR_ACT_TO_TBL)
return 0;
ns_id = zebra_ns_id_get(netnspath);
if (zserv_privs.change(ZPRIVS_LOWER))
zlog_err("Can't lower privileges");
+ if (ns_id == NS_UNKNOWN)
+ return;
ns_id_external = ns_map_nsid_with_external(ns_id, true);
/* if VRF with NS ID already present */
vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
if (ret != CMD_SUCCESS) {
zlog_warn("NS notify : failed to create NS %s", netnspath);
ns_map_nsid_with_external(ns_id, false);
+ vrf_delete(vrf);
return;
}
zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
int zebra_ptm_sock_read(struct thread *thread)
{
- int sock, done = 0;
+ int sock;
int rc;
errno = 0;
return -1;
/* PTM communicates in CSV format */
- while (!done) {
+ do {
rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data,
ZEBRA_PTM_MAX_SOCKBUF, NULL);
- if (rc <= 0)
- break;
- }
+ } while (rc > 0);
- if (rc <= 0) {
- if (((rc == 0) && !errno)
- || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
- zlog_warn("%s routing socket error: %s(%d) bytes %d",
- __func__, safe_strerror(errno), errno, rc);
-
- close(ptm_cb.ptm_sock);
- ptm_cb.ptm_sock = -1;
- zebra_ptm_reset_status(0);
- ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
- ptm_cb.reconnect_time,
- &ptm_cb.t_timer);
- return (-1);
- }
+ if (((rc == 0) && !errno)
+ || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) {
+ zlog_warn("%s routing socket error: %s(%d) bytes %d",
+ __func__, safe_strerror(errno), errno, rc);
+
+ close(ptm_cb.ptm_sock);
+ ptm_cb.ptm_sock = -1;
+ zebra_ptm_reset_status(0);
+ ptm_cb.t_timer = NULL;
+ thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ ptm_cb.reconnect_time,
+ &ptm_cb.t_timer);
+ return (-1);
}
ptm_cb.t_read = NULL;
if (!re)
return 0;
- assert(!src_p || afi == AFI_IP6);
+ assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
/* Lookup table. */
table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table);
char buf2[INET6_ADDRSTRLEN];
rib_dest_t *dest;
- assert(!src_p || afi == AFI_IP6);
+ assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
/* Lookup table. */
table = zebra_vrf_table_with_table_id(afi, safi, vrf_id, table_id);
/* 'match tag TAG'
* Match function return 1 if match is success else return 0
*/
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
route_map_object_t type, void *object)
{
route_tag_t *tag;
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_interface(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* Match function return 1 if match is success else return zero. */
static route_map_result_t route_match_ip_next_hop(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ip next-hop prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_ip_address(void *rule,
- struct prefix *prefix,
+ const struct prefix *prefix,
route_map_object_t type,
void *object)
{
/* `match ip address prefix-list PREFIX_LIST' */
static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
/* `match ip address prefix-len PREFIXLEN' */
static route_map_result_t
-route_match_address_prefix_len(void *rule, struct prefix *prefix,
+route_match_address_prefix_len(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
uint32_t *prefixlen = (uint32_t *)rule;
/* `match ip nexthop prefix-len PREFIXLEN' */
static route_map_result_t
-route_match_ip_nexthop_prefix_len(void *rule, struct prefix *prefix,
+route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
uint32_t *prefixlen = (uint32_t *)rule;
/* `match source-protocol PROTOCOL' */
static route_map_result_t route_match_source_protocol(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
/* `source-instance` */
static route_map_result_t route_match_source_instance(void *rule,
- struct prefix *prefix,
+ const struct prefix *p,
route_map_object_t type,
void *object)
{
/* `set src A.B.C.D' */
/* Set src. */
-static route_map_result_t route_set_src(void *rule, struct prefix *prefix,
+static route_map_result_t route_set_src(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
struct nh_rmap_obj *nh_data;
rmap = route_map_lookup_by_name(
proto_rm[family][ZEBRA_ROUTE_MAX]);
if (rmap) {
- ret = route_map_apply(rmap, (struct prefix *)p,
- RMAP_ZEBRA, &nh_obj);
+ ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
}
return (ret);
route_map_result_t
zebra_import_table_route_map_check(int family, int re_type, uint8_t instance,
- struct prefix *p, struct nexthop *nexthop,
+ const struct prefix *p,
+ struct nexthop *nexthop,
vrf_id_t vrf_id, route_tag_t tag,
const char *rmap_name)
{
}
route_map_result_t zebra_nht_route_map_check(int family, int client_proto,
- struct prefix *p,
+ const struct prefix *p,
struct route_entry *re,
struct nexthop *nexthop)
{
if (!rmap && nht_rm[family][ZEBRA_ROUTE_MAX])
rmap = route_map_lookup_by_name(
nht_rm[family][ZEBRA_ROUTE_MAX]);
- if (rmap) {
+ if (rmap)
ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
- }
- return (ret);
+ return ret;
}
static void zebra_route_map_mark_update(const char *rmap_name)
extern route_map_result_t
zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance,
- struct prefix *p, struct nexthop *nexthop,
+ const struct prefix *p,
+ struct nexthop *nexthop,
vrf_id_t vrf_id, route_tag_t tag,
const char *rmap_name);
extern route_map_result_t
const struct prefix *p, struct nexthop *nexthop,
vrf_id_t vrf_id, route_tag_t tag);
extern route_map_result_t
-zebra_nht_route_map_check(int family, int client_proto, struct prefix *p,
+zebra_nht_route_map_check(int family, int client_proto, const struct prefix *p,
struct route_entry *, struct nexthop *nexthop);
break;
}
- if (re->vrf_id != nexthop->vrf_id) {
+ if ((re->vrf_id != nexthop->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
struct vrf *vrf =
vrf_lookup_by_id(nexthop->vrf_id);
break;
}
- if (nexthop->vrf_id != re->vrf_id) {
+ if ((nexthop->vrf_id != re->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
struct vrf *vrf =
vrf_lookup_by_id(nexthop->vrf_id);
break;
}
- if (nexthop->vrf_id != re->vrf_id) {
+ if ((nexthop->vrf_id != re->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
if (vrf)
json = json_object_new_object();
/* Show all routes. */
- for (rn = route_top(table); rn; rn = route_next(rn)) {
+ for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
dest = rib_dest_from_rnode(rn);
RNODE_FOREACH_RE (rn, re) {
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
vty_out(vty, " Default-gateway Mac ");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
+ vty_out(vty, " Remote-gateway Mac ");
+
vty_out(vty, "\n");
/* print all the associated neigh */
vty_out(vty, " Neighbors:\n");
return -1;
vxl = &zif->l2info.vxl;
- sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
+ sticky = CHECK_FLAG(mac->flags,
+ (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)) ? 1 : 0;
return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr,
mac->fwd_info.r_vtep_ip, sticky);
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
uint8_t sticky = 0;
+ u_char remote_gw = 0;
uint8_t flags = 0;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
/* Get flags - sticky mac and/or gateway mac */
STREAM_GETC(s, flags);
sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
l++;
if (IS_ZEBRA_DEBUG_VXLAN)
if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|| (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0)
!= sticky
+ || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0)
+ != remote_gw
|| !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip))
update_mac = 1;
else
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ if (remote_gw)
+ SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
+
zvni_process_neigh_on_remote_mac_add(zvni, mac);
/* Install the entry. */
#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
#define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */
#define ZEBRA_MAC_DEF_GW 0x20
+/* remote VTEP advertised MAC as default GW */
+#define ZEBRA_MAC_REMOTE_DEF_GW 0x40
/* Local or remote info. */
union {
* sock
* client's socket file descriptor
*/
-static void zserv_client_create(int sock)
+static struct zserv *zserv_client_create(int sock)
{
struct zserv *client;
int i;
/* start pthread */
frr_pthread_run(client->pthread, NULL);
+
+ return client;
}
/*
struct zserv *client = NULL;
struct thread t;
- zserv_client_create(-1);
-
- frr_pthread_stop(client->pthread, NULL);
- frr_pthread_destroy(client->pthread);
- client->pthread = NULL;
-
- t.arg = client;
-
fd = open(input, O_RDONLY | O_NONBLOCK);
t.u.fd = fd;
- zserv_read(&t);
-
- close(fd);
+ zserv_client_create(fd);
}
#endif