struct vty *vty;
struct in_addr vtep_ip;
json_object *json;
+ int detail;
};
static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
struct vty *vty, struct in_addr vtep_ip,
- json_object *json)
+ json_object *json, int detail)
{
struct bgp_node *rn;
struct bgp_path_info *pi;
struct bgp_table *table;
- int header = 1;
+ int header = detail ? 0 : 1;
uint64_t tbl_ver;
uint32_t prefix_cnt, path_cnt;
if (json)
json_path = json_object_new_array();
- route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, json_path);
+ if (detail)
+ route_vty_out_detail(vty, bgp, &rn->p, pi,
+ AFI_L2VPN, SAFI_EVPN,
+ json_path);
+ else
+ route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
+ json_path);
if (json)
json_object_array_add(json_paths, json_path);
vty_out(vty, "\nDisplayed %u prefixes (%u paths)%s\n",
prefix_cnt, path_cnt,
type ? " (of requested type)" : "");
+ vty_out(vty, "\n");
}
}
vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
}
- show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni);
+ show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni,
+ wctx->detail);
if (json)
json_object_object_add(json, vni_str, json_vni);
* Display EVPN routes for all VNIs - vty handler.
*/
static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
- struct in_addr vtep_ip, json_object *json)
+ struct in_addr vtep_ip, json_object *json,
+ int detail)
{
uint32_t num_vnis;
struct vni_walk_ctx wctx;
wctx.vty = vty;
wctx.vtep_ip = vtep_ip;
wctx.json = json;
+ wctx.detail = detail;
hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *,
void *))show_vni_routes_hash,
&wctx);
}
/* Walk this VNI's route table and display appropriate routes. */
- show_vni_routes(bgp, vpn, type, vty, vtep_ip, json);
+ show_vni_routes(bgp, vpn, type, vty, vtep_ip, json, 0);
}
/*
*/
DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
show_bgp_l2vpn_evpn_route_vni_all_cmd,
- "show bgp l2vpn evpn route vni all [vtep A.B.C.D] [json]",
+ "show bgp l2vpn evpn route vni all [detail] [vtep A.B.C.D] [json]",
SHOW_STR
BGP_STR
L2VPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n"
"All VNIs\n"
+ "Print Detailed Output\n"
"Remote VTEP\n"
"Remote VTEP IP address\n"
JSON_STR)
int idx = 0;
bool uj = false;
json_object *json = NULL;
+ /* Detail Adjust. Adjust indexes according to detail option */
+ int da = 0;
bgp = bgp_get_evpn();
if (!bgp)
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
+ if (argv_find(argv, argc, "detail", &da))
+ da = 1;
+
+ /* vtep-ip position depends on detail option */
vtep_ip.s_addr = 0;
- if ((!uj && (argc == (idx + 1 + 5) && argv[idx + 5]->arg))
- || (uj && (argc == (idx + 1 + 6) && argv[idx + 5]->arg))) {
- if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
+ if ((!uj && (argc == (idx + 1 + 5 + da) && argv[idx + 5 + da]->arg))
+ || (uj
+ && (argc == (idx + 1 + 6 + da) && argv[idx + 5 + da]->arg))) {
+ if (!inet_aton(argv[idx + 5 + da]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
}
- evpn_show_routes_vni_all(vty, bgp, vtep_ip, json);
+ evpn_show_routes_vni_all(vty, bgp, vtep_ip, json, da);
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
"Originating Router IP address\n")
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
- "show bgp evpn route vni all [vtep A.B.C.D]",
+ "show bgp evpn route vni all [detail] [vtep A.B.C.D]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n"
"All VNIs\n"
+ "Print Detailed Output\n"
"Remote VTEP\n"
"Remote VTEP IP address\n")
if (display == NLRI_STRING_FORMAT_LARGE) {
struct bgp_path_info_extra *extra =
bgp_path_info_extra_get(path);
+ bool list_began = false;
- if (listcount(extra->bgp_fs_pbr) ||
- listcount(extra->bgp_fs_iprule)) {
+ if (extra->bgp_fs_pbr && listcount(extra->bgp_fs_pbr)) {
struct listnode *node;
struct bgp_pbr_match_entry *bpme;
- struct bgp_pbr_rule *bpr;
struct bgp_pbr_match *bpm;
- bool list_began = false;
struct list *list_bpm;
list_bpm = list_new();
vty_out(vty, ", ");
vty_out(vty, "%s", bpm->ipset_name);
}
+ list_delete(&list_bpm);
+ }
+ if (extra->bgp_fs_iprule && listcount(extra->bgp_fs_iprule)) {
+ struct listnode *node;
+ struct bgp_pbr_rule *bpr;
+
+ if (!list_began)
+ vty_out(vty, "\tinstalled in PBR");
for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule,
node, bpr)) {
if (!bpr->action)
if (list_began)
vty_out(vty, ")");
vty_out(vty, "\n");
- list_delete(&list_bpm);
- } else
+ }
+ if (!list_began)
vty_out(vty, "\tnot installed in PBR\n");
}
}
/* unlink path to bpme */
path = (struct bgp_path_info *)bpr->path;
extra = bgp_path_info_extra_get(path);
- listnode_delete(extra->bgp_fs_iprule, bpr);
+ if (extra->bgp_fs_iprule)
+ listnode_delete(extra->bgp_fs_iprule, bpr);
bpr->path = NULL;
}
}
/* unlink path to bpme */
path = (struct bgp_path_info *)bpme->path;
extra = bgp_path_info_extra_get(path);
- listnode_delete(extra->bgp_fs_pbr, bpme);
+ if (extra->bgp_fs_pbr)
+ listnode_delete(extra->bgp_fs_pbr, bpme);
bpme->path = NULL;
}
}
struct bgp_path_info_extra *extra =
bgp_path_info_extra_get(path);
- if (extra && listnode_lookup(extra->bgp_fs_iprule,
- bpr)) {
+ if (extra &&
+ listnode_lookup_nocheck(extra->bgp_fs_iprule,
+ bpr)) {
if (BGP_DEBUG(pbr, PBR_ERROR))
zlog_err("%s: entry %p/%p already "
"installed in bgp pbr iprule",
struct bgp_path_info_extra *extra =
bgp_path_info_extra_get(path);
- if (extra && listnode_lookup(extra->bgp_fs_pbr, bpme)) {
+ if (extra &&
+ listnode_lookup_nocheck(extra->bgp_fs_pbr, bpme)) {
if (BGP_DEBUG(pbr, PBR_ERROR))
zlog_err(
"%s: entry %p/%p already installed in bgp pbr",
sizeof(struct bgp_path_info_extra));
new->label[0] = MPLS_INVALID_LABEL;
new->num_labels = 0;
- new->bgp_fs_pbr = list_new();
- new->bgp_fs_iprule = list_new();
+ new->bgp_fs_pbr = NULL;
+ new->bgp_fs_iprule = NULL;
return new;
}
/* link bgp_info to bgp_pbr */
path = (struct bgp_path_info *)bgp_pbr->path;
extra = bgp_path_info_extra_get(path);
- listnode_add(extra->bgp_fs_iprule, bgp_pbr);
+ listnode_add_force(&extra->bgp_fs_iprule,
+ bgp_pbr);
}
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%s: Received RULE_INSTALLED",
/* link bgp_path_info to bpme */
path = (struct bgp_path_info *)bgp_pbime->path;
extra = bgp_path_info_extra_get(path);
- listnode_add(extra->bgp_fs_pbr, bgp_pbime);
+ listnode_add_force(&extra->bgp_fs_pbr, bgp_pbime);
}
break;
case ZAPI_IPSET_ENTRY_FAIL_REMOVE:
DEFPY(isis_default_originate, isis_default_originate_cmd,
"[no] default-information originate <ipv4|ipv6>$ip"
" <level-1|level-2>$level [always]$always"
- " [<metric (0-16777215)$metric|route-map WORD$rmap>]",
+ " [{metric (0-16777215)$metric|route-map WORD$rmap}]",
NO_STR
"Control distribution of default information\n"
"Distribute a default route\n"
nb_cli_enqueue_change(vty, "./route-map",
rmap ? NB_OP_MODIFY : NB_OP_DESTROY,
rmap ? rmap : NULL);
- nb_cli_enqueue_change(vty, "./metric",
- metric ? NB_OP_MODIFY : NB_OP_DESTROY,
- metric ? metric_str : NULL);
+ nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY,
+ metric_str ? metric_str : NULL);
if (strmatch(ip, "ipv6") && !always) {
vty_out(vty,
"Zebra doesn't implement default-originate for IPv6 yet\n");
const char *family, const char *level,
bool show_defaults)
{
- const char *metric;
-
vty_out(vty, " default-information originate %s %s", family, level);
if (yang_dnode_get_bool(dnode, "./always"))
vty_out(vty, " always");
if (yang_dnode_exists(dnode, "./route-map"))
vty_out(vty, " route-map %s",
yang_dnode_get_string(dnode, "./route-map"));
- else if (yang_dnode_exists(dnode, "./metric")) {
- metric = yang_dnode_get_string(dnode, "./metric");
- if (show_defaults || !yang_dnode_is_default(dnode, "./metric"))
- vty_out(vty, " metric %s", metric);
- }
+ if (show_defaults || !yang_dnode_is_default(dnode, "./metric"))
+ vty_out(vty, " metric %s",
+ yang_dnode_get_string(dnode, "./metric"));
+
vty_out(vty, "\n");
}
"[no] redistribute <ipv4|ipv6>$ip " PROTO_REDIST_STR
"$proto"
" <level-1|level-2>$level"
- " [<metric (0-16777215)|route-map WORD>]",
+ " [{metric (0-16777215)|route-map WORD}]",
NO_STR REDIST_STR
"Redistribute IPv4 routes\n"
"Redistribute IPv6 routes\n" PROTO_REDIST_HELP
nb_cli_enqueue_change(vty, "./route-map",
route_map ? NB_OP_MODIFY : NB_OP_DESTROY,
route_map ? route_map : NULL);
- nb_cli_enqueue_change(vty, "./metric",
- metric ? NB_OP_MODIFY : NB_OP_DESTROY,
- metric ? metric_str : NULL);
+ nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY,
+ metric_str ? metric_str : NULL);
}
return nb_cli_apply_changes(
}
static void vty_print_redistribute(struct vty *vty, struct lyd_node *dnode,
- const char *family)
+ bool show_defaults, const char *family)
{
const char *level = yang_dnode_get_string(dnode, "./level");
const char *protocol = yang_dnode_get_string(dnode, "./protocol");
vty_out(vty, " redistribute %s %s %s", family, protocol, level);
- if (yang_dnode_exists(dnode, "./metric"))
+ if (show_defaults || !yang_dnode_is_default(dnode, "./metric"))
vty_out(vty, " metric %s",
yang_dnode_get_string(dnode, "./metric"));
- else if (yang_dnode_exists(dnode, "./route-map"))
+ if (yang_dnode_exists(dnode, "./route-map"))
vty_out(vty, " route-map %s",
yang_dnode_get_string(dnode, "./route-map"));
vty_out(vty, "\n");
void cli_show_isis_redistribute_ipv4(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- vty_print_redistribute(vty, dnode, "ipv4");
+ vty_print_redistribute(vty, dnode, show_defaults, "ipv4");
}
void cli_show_isis_redistribute_ipv6(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- vty_print_redistribute(vty, dnode, "ipv6");
+ vty_print_redistribute(vty, dnode, show_defaults, "ipv6");
}
/*
if (yang_dnode_exists(dnode, "./metric"))
metric = yang_dnode_get_uint32(dnode, "./metric");
- else if (yang_dnode_exists(dnode, "./route-map"))
+ if (yang_dnode_exists(dnode, "./route-map"))
routemap = yang_dnode_get_string(dnode, "./route-map");
isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap,
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv4_metric_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
/*
* XPath: /frr-isisd:isis/instance/default-information-originate/ipv6
*/
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv6_metric_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
/*
* XPath: /frr-isisd:isis/instance/redistribute/ipv4
*/
if (yang_dnode_exists(dnode, "./metric"))
metric = yang_dnode_get_uint32(dnode, "./metric");
- else if (yang_dnode_exists(dnode, "./route-map"))
+ if (yang_dnode_exists(dnode, "./route-map"))
routemap = yang_dnode_get_string(dnode, "./route-map");
isis_redist_set(area, level, family, type, metric, routemap, 0);
return NB_OK;
}
-static int
-isis_instance_redistribute_ipv4_metric_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
/*
* XPath: /frr-isisd:isis/instance/redistribute/ipv6
*/
return NB_OK;
}
-static int
-isis_instance_redistribute_ipv6_metric_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
/*
* XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast
*/
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric",
.cbs.modify = isis_instance_default_information_originate_ipv4_metric_modify,
- .cbs.destroy = isis_instance_default_information_originate_ipv4_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6",
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric",
.cbs.modify = isis_instance_default_information_originate_ipv6_metric_modify,
- .cbs.destroy = isis_instance_default_information_originate_ipv6_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4",
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric",
.cbs.modify = isis_instance_redistribute_ipv4_metric_modify,
- .cbs.destroy = isis_instance_redistribute_ipv4_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6",
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric",
.cbs.modify = isis_instance_redistribute_ipv6_metric_modify,
- .cbs.destroy = isis_instance_redistribute_ipv6_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast",
DEFUN (isis_redistribute,
isis_redistribute_cmd,
"redistribute <ipv4|ipv6> " PROTO_REDIST_STR
- " [<metric (0-16777215)|route-map WORD>]",
+ " [{metric (0-16777215)|route-map WORD}]",
REDIST_STR
"Redistribute IPv4 routes\n"
"Redistribute IPv6 routes\n"
{
int idx_afi = 1;
int idx_protocol = 2;
- int idx_metric_rmap = fabricd ? 3 : 4;
+ int idx_metric_rmap = 1;
VTY_DECLVAR_CONTEXT(isis_area, area);
int family;
int afi;
return CMD_WARNING_CONFIG_FAILED;
}
- if (argc > idx_metric_rmap + 1) {
- if (argv[idx_metric_rmap + 1]->arg[0] == '\0')
- return CMD_WARNING_CONFIG_FAILED;
-
- if (strmatch(argv[idx_metric_rmap]->text, "metric")) {
- char *endp;
- metric = strtoul(argv[idx_metric_rmap + 1]->arg, &endp,
- 10);
+ if (argv_find(argv, argc, "metric", &idx_metric_rmap)) {
+ metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL, 10);
+ }
- if (*endp != '\0')
- return CMD_WARNING_CONFIG_FAILED;
- } else {
- routemap = argv[idx_metric_rmap + 1]->arg;
- }
+ idx_metric_rmap = 1;
+ if (argv_find(argv, argc, "route-map", &idx_metric_rmap)) {
+ routemap = argv[idx_metric_rmap + 1]->arg;
}
isis_redist_set(area, level, family, type, metric, routemap, 0);
DEFUN (isis_default_originate,
isis_default_originate_cmd,
"default-information originate <ipv4|ipv6>"
- " [always] [<metric (0-16777215)|route-map WORD>]",
+ " [always] [{metric (0-16777215)|route-map WORD}]",
"Control distribution of default information\n"
"Distribute a default route\n"
"Distribute default route for IPv4\n"
{
int idx_afi = 2;
int idx_always = fabricd ? 3 : 4;
- int idx_metric_rmap = fabricd ? 3 : 4;
+ int idx_metric_rmap = 1;
VTY_DECLVAR_CONTEXT(isis_area, area);
int family;
int originate_type = DEFAULT_ORIGINATE;
idx_metric_rmap++;
}
- if (argc > idx_metric_rmap) {
- if (strmatch(argv[idx_metric_rmap]->text, "metric"))
- metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL,
- 10);
- else
- routemap = argv[idx_metric_rmap + 1]->arg;
+ if (argv_find(argv, argc, "metric", &idx_metric_rmap)) {
+ metric = strtoul(argv[idx_metric_rmap + 1]->arg, NULL, 10);
+ }
+
+ idx_metric_rmap = 1;
+ if (argv_find(argv, argc, "route-map", &idx_metric_rmap)) {
+ routemap = argv[idx_metric_rmap + 1]->arg;
}
if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS) {
return NULL;
}
+struct listnode *listnode_lookup_nocheck(struct list *list, void *data)
+{
+ if (!list)
+ return NULL;
+ return listnode_lookup(list, data);
+}
+
void list_delete_node(struct list *list, struct listnode *node)
{
if (node->prev)
XFREE(MTYPE_TMP, items);
}
+
+void listnode_add_force(struct list **list, void *val)
+{
+ if (*list == NULL)
+ *list = list_new();
+ return listnode_add(*list, val);
+}
(L)->count--; \
} while (0)
+extern struct listnode *listnode_lookup_nocheck(struct list *list, void *data);
+
+extern void listnode_add_force(struct list **list, void *val);
+
#ifdef __cplusplus
}
#endif
}
}
-static int vrf_default_accepts_vrf(int type)
-{
- const char *fname = NULL;
- char buf[32] = {0x0};
- int ret = 0;
- FILE *fd = NULL;
-
- /*
- * TCP & UDP services running in the default VRF context (ie., not bound
- * to any VRF device) can work across all VRF domains by enabling the
- * tcp_l3mdev_accept and udp_l3mdev_accept sysctl options:
- * sysctl -w net.ipv4.tcp_l3mdev_accept=1
- * sysctl -w net.ipv4.udp_l3mdev_accept=1
- */
- if (type == SOCK_STREAM)
- fname = "/proc/sys/net/ipv4/tcp_l3mdev_accept";
- else if (type == SOCK_DGRAM)
- fname = "/proc/sys/net/ipv4/udp_l3mdev_accept";
- else
- return ret;
- fd = fopen(fname, "r");
- if (fd == NULL)
- return ret;
- fgets(buf, 32, fd);
- ret = atoi(buf);
- fclose(fd);
- return ret;
-}
-
/* Create a socket for the VRF. */
int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
const char *interfacename)
flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)",
__func__, vrf_id, safe_strerror(errno));
- if (ret > 0 && interfacename && vrf_default_accepts_vrf(type)) {
- zlog_err("VRF socket not used since net.ipv4.%s_l3mdev_accept != 0",
- (type == SOCK_STREAM ? "tcp" : "udp"));
- errno = EEXIST; /* not sure if this is the best error... */
- return -2;
- }
-
ret = socket(domain, type, protocol);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
"Source/RP address\n"
"Multicast Group address\n")
{
- 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.u.prefix4 = grp_addr;
memset(&nexthop, 0, sizeof(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, &nht_p,
- &grp, 0);
+ result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop, &nht_p, &grp, 0);
if (!result) {
vty_out(vty,
hash_get(pnc->upstream_hash, up, hash_alloc_intern);
if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) {
- memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
+ if (out_pnc)
+ memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
return 1;
}
continue;
// Compute PIM RPF using cached nexthop
- if (!pim_ecmp_nexthop_search(pim, pnc,
- &rp_info->rp.source_nexthop,
- &rp_info->rp.rpf_addr, &rp_info->group,
- 1))
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
+ &rp_info->rp.rpf_addr,
+ &rp_info->group, 1))
pim_rp_nexthop_del(rp_info);
}
}
return hash_val;
}
-int pim_ecmp_nexthop_search(struct pim_instance *pim,
- struct pim_nexthop_cache *pnc,
- struct pim_nexthop *nexthop, struct prefix *src,
- struct prefix *grp, int neighbor_needed)
+static int pim_ecmp_nexthop_search(struct pim_instance *pim,
+ struct pim_nexthop_cache *pnc,
+ struct pim_nexthop *nexthop,
+ struct prefix *src, struct prefix *grp,
+ int neighbor_needed)
{
struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL;
struct interface *ifps[MULTIPATH_NUM];
nexthops_free(pnc->nexthop);
pnc->nexthop = NULL;
}
+ SET_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED);
if (PIM_DEBUG_PIM_NHT) {
char buf[PREFIX2STR_BUFFER];
struct pim_nexthop *nexthop, struct prefix *src,
struct prefix *grp, int neighbor_needed)
{
+ struct pim_nexthop_cache *pnc;
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
struct pim_neighbor *nbrs[MULTIPATH_NUM], *nbr = NULL;
+ struct pim_rpf rpf;
int num_ifindex;
struct interface *ifps[MULTIPATH_NUM], *ifp;
int first_ifindex;
nexthop->last_lookup_time);
}
+ 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 = src->u.prefix4;
+
+ pnc = pim_nexthop_cache_find(pim, &rpf);
+ if (pnc) {
+ if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED))
+ return pim_ecmp_nexthop_search(pim, pnc, nexthop, src, grp,
+ neighbor_needed);
+ }
+
memset(nexthop_tab, 0,
sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
num_ifindex =
if (PIM_DEBUG_PIM_NHT)
pim_inet4_dump("<addr?>", src->u.prefix4, addr_str,
sizeof(addr_str));
+
+ memset(&nhop, 0, sizeof(nhop));
if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 0)) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
int64_t last_update;
uint16_t flags;
#define PIM_NEXTHOP_VALID (1 << 0)
+#define PIM_NEXTHOP_ANSWER_RECEIVED (1 << 1)
struct list *rp_list;
struct hash *upstream_hash;
struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
struct pim_rpf *rpf);
uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp);
-int pim_ecmp_nexthop_search(struct pim_instance *pim,
- struct pim_nexthop_cache *pnc,
- 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 prefix *src,
struct prefix *grp, int neighbor_needed);
char buffer[BUFSIZ];
struct prefix nht_p;
struct prefix temp;
- struct pim_nexthop_cache pnc;
struct route_node *rn;
struct pim_upstream *up;
struct listnode *upnode;
}
}
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
- &pnc)) {
- if (!pim_ecmp_nexthop_search(
- pim, &pnc,
- &rp_all->rp.source_nexthop, &nht_p,
- &rp_all->group, 1))
- return PIM_RP_NO_PATH;
- } else {
- if (!pim_ecmp_nexthop_lookup(
- pim, &rp_all->rp.source_nexthop,
- &nht_p, &rp_all->group, 1))
- return PIM_RP_NO_PATH;
- }
pim_rp_check_interfaces(pim, rp_all);
pim_rp_refresh_group_to_rp_mapping(pim);
+
+ pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
+ NULL);
+ if (!pim_ecmp_nexthop_lookup(pim,
+ &rp_all->rp.source_nexthop,
+ &nht_p, &rp_all->group, 1))
+ return PIM_RP_NO_PATH;
+
return PIM_SUCCESS;
}
}
}
+ pim_rp_check_interfaces(pim, rp_info);
+ pim_rp_refresh_group_to_rp_mapping(pim);
+
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
__PRETTY_FUNCTION__, buf, buf1);
}
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) {
- if (!pim_ecmp_nexthop_search(pim, &pnc,
- &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1))
- return PIM_RP_NO_PATH;
- } else {
- if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1))
- return PIM_RP_NO_PATH;
- }
+ pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
+ &rp_info->group, 1))
+ return PIM_RP_NO_PATH;
- pim_rp_check_interfaces(pim, rp_info);
- pim_rp_refresh_group_to_rp_mapping(pim);
return PIM_SUCCESS;
}
struct listnode *node;
struct rp_info *rp_info;
struct prefix nht_p;
- struct pim_nexthop_cache pnc;
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc))
- pim_ecmp_nexthop_search(pim, &pnc,
- &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1);
- else {
- if (PIM_DEBUG_PIM_NHT_RP) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&nht_p, buf, sizeof(buf));
+ pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
+ 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(
- "%s: NHT Local Nexthop not found for RP %s ",
- __PRETTY_FUNCTION__, buf);
- }
- 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");
- }
+ "Unable to lookup nexthop for rp specified");
}
}
if (rp_info) {
struct prefix nht_p;
- struct pim_nexthop_cache pnc;
+
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
"%s: NHT Register RP addr %s grp %s with Zebra",
__PRETTY_FUNCTION__, buf, buf1);
}
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc))
- pim_ecmp_nexthop_search(pim, &pnc,
- &rp_info->rp.source_nexthop,
- &nht_p, &rp_info->group, 1);
- else {
- if (PIM_DEBUG_PIM_NHT_RP) {
- char buf[PREFIX2STR_BUFFER];
- char buf1[PREFIX2STR_BUFFER];
- prefix2str(&nht_p, buf, sizeof(buf));
- prefix2str(&g, buf1, sizeof(buf1));
- zlog_debug(
- "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
- __PRETTY_FUNCTION__, buf, buf1);
- }
- pim_rpf_set_refresh_time(pim);
- (void)pim_ecmp_nexthop_lookup(
- pim, &rp_info->rp.source_nexthop, &nht_p,
- &rp_info->group, 1);
- }
+
+ pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
+ pim_rpf_set_refresh_time(pim);
+ (void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
return (&rp_info->rp);
}
struct pim_rpf *rpf = &up->rpf;
struct pim_rpf saved;
struct prefix nht_p;
- struct pim_nexthop_cache pnc;
struct prefix src, grp;
bool neigh_needed = true;
grp.family = AF_INET;
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, neigh_needed))
- return PIM_RPF_FAILURE;
- }
- } else {
- if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src,
- &grp, neigh_needed))
- return PIM_RPF_FAILURE;
- }
+ pim_find_or_track_nexthop(pim, &nht_p, up, NULL, NULL);
+ if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src, &grp,
+ neigh_needed))
+ return PIM_RPF_FAILURE;
rpf->rpf_addr.family = AF_INET;
rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
if (!starup
|| up->rpf.source_nexthop
.interface != starup->rpf.source_nexthop.interface) {
+ struct pim_upstream *starup = up->parent;
+
if (PIM_DEBUG_TRACE)
zlog_debug(
"%s: %s RPF_interface(S) != RPF_interface(RP(G))",
__PRETTY_FUNCTION__, up->sg_str);
up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
+
+ pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
return;
}
if (!source->source_channel_oil) {
struct in_addr vif_source;
struct prefix nht_p, src, grp;
- struct pim_nexthop_cache out_pnc;
struct pim_nexthop nexthop;
struct pim_upstream *up = NULL;
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
nht_p.u.prefix4 = vif_source;
- memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
src.family = AF_INET;
src.prefixlen = IPV4_MAX_BITLEN;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = sg.grp;
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
- &out_pnc)) {
- if (out_pnc.nexthop_num) {
- up = pim_upstream_find(pim, &sg);
- memset(&nexthop, 0, sizeof(nexthop));
- if (up)
- memcpy(&nexthop,
- &up->rpf.source_nexthop,
- sizeof(struct pim_nexthop));
- pim_ecmp_nexthop_search(pim, &out_pnc,
- &nexthop,
- &src, &grp, 0);
- if (nexthop.interface)
- input_iface_vif_index =
+ up = pim_upstream_find(pim, &sg);
+ if (up) {
+ memcpy(&nexthop, &up->rpf.source_nexthop,
+ sizeof(struct pim_nexthop));
+ pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
+ &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index =
pim_if_find_vifindex_by_ifindex(
- pim,
- nexthop.interface->ifindex);
- } else {
- if (PIM_DEBUG_ZEBRA) {
- char buf1[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<source?>",
- nht_p.u.prefix4, buf1,
- sizeof(buf1));
- pim_inet4_dump("<source?>",
- grp.u.prefix4, buf2,
- sizeof(buf2));
- zlog_debug(
- "%s: NHT Nexthop not found for addr %s grp %s",
- __PRETTY_FUNCTION__, buf1,
- buf2);
- }
- }
+ pim,
+ nexthop.interface->ifindex);
} else
input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(pim, &src,
- &grp);
+ pim_ecmp_fib_lookup_if_vif_index(
+ pim, &src, &grp);
if (PIM_DEBUG_ZEBRA) {
char buf2[INET_ADDRSTRLEN];
*/
if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) {
struct prefix nht_p, src, grp;
- struct pim_nexthop_cache out_pnc;
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
grp.family = AF_INET;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = up->sg.grp;
- memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
-
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
- &out_pnc)) {
- if (out_pnc.nexthop_num) {
- src.family = AF_INET;
- src.prefixlen = IPV4_MAX_BITLEN;
- src.u.prefix4 =
- up->upstream_addr; // RP or Src address
- grp.family = AF_INET;
- grp.prefixlen = IPV4_MAX_BITLEN;
- grp.u.prefix4 = up->sg.grp;
- // Compute PIM RPF using Cached nexthop
- if (pim_ecmp_nexthop_search(
- pim, &out_pnc,
- &up->rpf.source_nexthop, &src, &grp,
- 0))
- input_iface_vif_index =
- pim_if_find_vifindex_by_ifindex(
- pim,
- up->rpf.source_nexthop
- .interface->ifindex);
- else {
- if (PIM_DEBUG_TRACE)
- zlog_debug(
- "%s: Nexthop selection failed for %s ",
- __PRETTY_FUNCTION__,
- up->sg_str);
- }
- } else {
- if (PIM_DEBUG_ZEBRA) {
- char buf1[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>",
- nht_p.u.prefix4, buf1,
- sizeof(buf1));
- pim_inet4_dump("<source?>",
- grp.u.prefix4, buf2,
- sizeof(buf2));
- zlog_debug(
- "%s: NHT pnc is NULL for addr %s grp %s",
- __PRETTY_FUNCTION__, buf1,
- buf2);
- }
- }
- } else
- input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(pim, &src,
- &grp);
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = up->sg.src;
+
+ if (pim_ecmp_nexthop_lookup(pim, &up->rpf.source_nexthop, &src,
+ &grp, 0))
+ input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
+ pim, up->rpf.source_nexthop.interface->ifindex);
if (input_iface_vif_index < 1) {
if (PIM_DEBUG_PIM_TRACE) {
grouping redistribute-attributes {
description
"Common optional attributes of any redistribute entry.";
- choice attribute {
- leaf route-map {
- type string {
- length "1..max";
- }
- description
- "Applies the conditions of the specified route-map to routes that
- are redistributed into this routing instance.";
+ leaf route-map {
+ type string {
+ length "1..max";
}
+ description
+ "Applies the conditions of the specified route-map to routes that
+ are redistributed into this routing instance.";
+ }
- leaf metric {
- type uint32 {
- range "0..16777215";
- }
- default "0";
- description
- "Metric used for the redistributed route. If 0,
- the default-metric attribute is used instead.";
+ leaf metric {
+ type uint32 {
+ range "0..16777215";
}
+ default "0";
+ description
+ "Metric used for the redistributed route. If 0,
+ the default-metric attribute is used instead.";
}
}
"Area-tag associated to this circuit.";
}
- leaf circuit-type {
- type level;
- default "level-1-2";
- description
- "IS-type of this circuit.";
- }
-
leaf ipv4-routing {
type boolean;
default "false";
"Routing IS-IS IPv6 traffic over this circuit.";
}
+ leaf circuit-type {
+ type level;
+ default "level-1-2";
+ description
+ "IS-type of this circuit.";
+ }
+
container csnp-interval {
description
"Complete Sequence Number PDU (CSNP) generation interval.";
/* Limit number of pending, unprocessed updates */
_Atomic uint32_t dg_max_queued_updates;
+ /* Control whether system route notifications should be produced. */
+ bool dg_sys_route_notifs;
+
/* Limit number of new updates dequeued at once, to pace an
* incoming burst.
*/
return p;
}
+/* Enable system route notifications */
+void dplane_enable_sys_route_notifs(void)
+{
+ zdplane_info.dg_sys_route_notifs = true;
+}
+
/*
* Free a dataplane results context.
*/
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
+ case DPLANE_OP_SYS_ROUTE_ADD:
+ case DPLANE_OP_SYS_ROUTE_DELETE:
/* Free allocated nexthops */
if ((*pctx)->u.rinfo.zd_ng.nexthop) {
ret = "PW_UNINSTALL";
break;
+ case DPLANE_OP_SYS_ROUTE_ADD:
+ ret = "SYS_ROUTE_ADD";
+ break;
+ case DPLANE_OP_SYS_ROUTE_DELETE:
+ ret = "SYS_ROUTE_DEL";
+ break;
}
return ret;
ctx->u.rinfo.zd_afi = info->afi;
ctx->u.rinfo.zd_safi = info->safi;
- /* Extract ns info - can't use pointers to 'core' structs */
- zvrf = vrf_info_lookup(re->vrf_id);
- zns = zvrf->zns;
-
- dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
-
/* Copy nexthops; recursive info is included too */
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng.nexthop, NULL);
- /* TODO -- maybe use array of nexthops to avoid allocs? */
-
/* Ensure that the dplane's nexthops flags are clear. */
for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ /* Don't need some info when capturing a system notification */
+ if (op == DPLANE_OP_SYS_ROUTE_ADD ||
+ op == DPLANE_OP_SYS_ROUTE_DELETE) {
+ ret = AOK;
+ goto done;
+ }
+
+ /* Extract ns info - can't use pointers to 'core' structs */
+ zvrf = vrf_info_lookup(re->vrf_id);
+ zns = zvrf->zns;
+ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
+
/* Trying out the sequence number idea, so we can try to detect
* when a result is stale.
*/
return ret;
}
+/*
+ * Notify the dplane when system/connected routes change.
+ */
+enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
+ struct route_entry *re)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ /* Ignore this event unless a provider plugin has requested it. */
+ if (!zdplane_info.dg_sys_route_notifs) {
+ ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ goto done;
+ }
+
+ if (rn == NULL || re == NULL)
+ goto done;
+
+ ret = dplane_route_update_internal(rn, re, NULL,
+ DPLANE_OP_SYS_ROUTE_ADD);
+
+done:
+ return ret;
+}
+
+/*
+ * Notify the dplane when system/connected routes are deleted.
+ */
+enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
+ struct route_entry *re)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ /* Ignore this event unless a provider plugin has requested it. */
+ if (!zdplane_info.dg_sys_route_notifs) {
+ ret = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ goto done;
+ }
+
+ if (rn == NULL || re == NULL)
+ goto done;
+
+ ret = dplane_route_update_internal(rn, re, NULL,
+ DPLANE_OP_SYS_ROUTE_DELETE);
+
+done:
+ return ret;
+}
+
/*
* Enqueue LSP add for the dataplane.
*/
res = kernel_dplane_pw_update(ctx);
break;
+ /* Ignore system 'notifications' - the kernel already knows */
+ case DPLANE_OP_SYS_ROUTE_ADD:
+ case DPLANE_OP_SYS_ROUTE_DELETE:
+ res = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ break;
+
default:
atomic_fetch_add_explicit(
&zdplane_info.dg_other_errors, 1,
if (ctx == NULL)
break;
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("dplane provider '%s': op %s",
+ dplane_provider_get_name(prov),
+ dplane_op2str(dplane_ctx_get_op(ctx)));
+
dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
dplane_provider_enqueue_out_ctx(prov, ctx);
/* Pseudowire update */
DPLANE_OP_PW_INSTALL,
DPLANE_OP_PW_UNINSTALL,
+
+ /* System route notification */
+ DPLANE_OP_SYS_ROUTE_ADD,
+ DPLANE_OP_SYS_ROUTE_DELETE,
};
+/* Enable system route notifications */
+void dplane_enable_sys_route_notifs(void);
+
/*
* The dataplane context struct is used to exchange info between the main zebra
* context and the dataplane module(s). If these are two independent pthreads,
enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
struct route_entry *re);
+/* Notify the dplane when system/connected routes change */
+enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
+ struct route_entry *re);
+enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
+ struct route_entry *re);
+
/*
* Enqueue LSP change operations for the dataplane.
*/
break;
}
+ /* If this route is kernel/connected route, notify the dataplane. */
+ if (RIB_SYSTEM_ROUTE(re)) {
+ /* Notify dataplane */
+ dplane_sys_route_add(rn, re);
+ }
+
/* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
rnode_debug(rn, re->vrf_id,
&vtep_ip, p);
}
}
+
+ /* Notify dplane if system route changes */
+ if (RIB_SYSTEM_ROUTE(re))
+ dplane_sys_route_del(rn, same);
+
rib_delnode(rn, same);
}
handle_pw_result(ctx);
break;
+ case DPLANE_OP_SYS_ROUTE_ADD:
+ case DPLANE_OP_SYS_ROUTE_DELETE:
+ /* No further processing in zebra for these. */
+ dplane_ctx_fini(&ctx);
+ break;
+
default:
/* Don't expect this: just return the struct? */
dplane_ctx_fini(&ctx);