diff options
| -rw-r--r-- | eigrpd/eigrp_dump.c | 4 | ||||
| -rw-r--r-- | eigrpd/eigrp_vty.c | 156 | ||||
| -rw-r--r-- | lib/if.c | 2 | ||||
| -rw-r--r-- | lib/if.h | 2 | ||||
| -rw-r--r-- | lib/nexthop_group.c | 34 | ||||
| -rw-r--r-- | lib/nexthop_group.h | 3 | ||||
| -rw-r--r-- | lib/zclient.c | 2 | ||||
| -rw-r--r-- | ospfd/ospf_spf.c | 52 | ||||
| -rw-r--r-- | ospfd/ospf_spf.h | 1 | ||||
| -rw-r--r-- | ospfd/ospfd.h | 2 | ||||
| -rw-r--r-- | pbrd/pbr_map.c | 61 | ||||
| -rw-r--r-- | pbrd/pbr_map.h | 7 | ||||
| -rw-r--r-- | pbrd/pbr_nht.c | 292 | ||||
| -rw-r--r-- | pbrd/pbr_nht.h | 12 | ||||
| -rw-r--r-- | pbrd/pbr_vrf.c | 2 | ||||
| -rw-r--r-- | pbrd/pbr_vty.c | 31 | ||||
| -rw-r--r-- | pbrd/pbr_zebra.c | 1 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 14 |
18 files changed, 548 insertions, 130 deletions
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index 0874ce3f19..97de73116b 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -154,7 +154,7 @@ void show_ip_eigrp_interface_header(struct vty *vty, struct eigrp *eigrp) { vty_out(vty, - "\nEIGRP interfaces for AS(%d)\n\n %-10s %-10s %-10s %-6s %-12s %-7s %-14s %-12s %-8s %-8s %-8s\n %-39s %-12s %-7s %-14s %-12s %-8s\n", + "\nEIGRP interfaces for AS(%d)\n\n%-16s %-10s %-10s %-6s %-12s %-7s %-14s %-12s %-8s %-8s %-8s\n %-44s %-12s %-7s %-14s %-12s %-8s\n", eigrp->AS, "Interface", "Bandwidth", "Delay", "Peers", "Xmit Queue", "Mean", "Pacing Time", "Multicast", "Pending", "Hello", "Holdtime", "", "Un/Reliable", "SRTT", "Un/Reliable", @@ -164,7 +164,7 @@ void show_ip_eigrp_interface_header(struct vty *vty, struct eigrp *eigrp) void show_ip_eigrp_interface_sub(struct vty *vty, struct eigrp *eigrp, struct eigrp_interface *ei) { - vty_out(vty, "%-11s ", IF_NAME(ei)); + vty_out(vty, "%-16s ", IF_NAME(ei)); vty_out(vty, "%-11u", ei->params.bandwidth); vty_out(vty, "%-11u", ei->params.delay); vty_out(vty, "%-7u", ei->nbrs->count); diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index e4a499425b..4426cf67e9 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -101,6 +101,24 @@ static struct eigrp *eigrp_vty_get_eigrp(struct vty *vty, const char *vrf_name) return eigrp_lookup(vrf->vrf_id); } +static void eigrp_topology_helper(struct vty *vty, struct eigrp *eigrp, + const char *all) +{ + struct eigrp_prefix_entry *tn; + struct route_node *rn; + + show_ip_eigrp_topology_header(vty, eigrp); + + for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) { + if (!rn->info) + continue; + + tn = rn->info; + eigrp_vty_display_prefix_entry(vty, eigrp, tn, + all ? true : false); + } +} + DEFPY (show_ip_eigrp_topology_all, show_ip_eigrp_topology_all_cmd, "show ip eigrp [vrf NAME] topology [all-links$all]", @@ -112,28 +130,30 @@ DEFPY (show_ip_eigrp_topology_all, "Show all links in topology table\n") { struct eigrp *eigrp; - struct eigrp_prefix_entry *tn; - struct route_node *rn; - eigrp = eigrp_vty_get_eigrp(vty, vrf); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } + if (vrf && strncmp(vrf, "all", sizeof("all")) == 0) { + struct vrf *v; - show_ip_eigrp_topology_header(vty, eigrp); + RB_FOREACH (v, vrf_name_head, &vrfs_by_name) { + eigrp = eigrp_lookup(v->vrf_id); + if (!eigrp) + continue; - for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) { - if (!rn->info) - continue; + vty_out(vty, "VRF %s:\n", v->name); - tn = rn->info; - eigrp_vty_display_prefix_entry(vty, eigrp, tn, - all ? true : false); + eigrp_topology_helper(vty, eigrp, all); + } + } else { + eigrp = eigrp_vty_get_eigrp(vty, vrf); + if (eigrp == NULL) { + vty_out(vty, " EIGRP Routing Process not enabled\n"); + return CMD_SUCCESS; + } + + eigrp_topology_helper(vty, eigrp, all); } return CMD_SUCCESS; - } DEFPY (show_ip_eigrp_topology, @@ -152,6 +172,11 @@ DEFPY (show_ip_eigrp_topology, struct route_node *rn; struct prefix cmp; + if (vrf && strncmp(vrf, "all", sizeof("all")) == 0) { + vty_out(vty, "Specifying vrf `all` for a particular address/prefix makes no sense\n"); + return CMD_SUCCESS; + } + eigrp = eigrp_vty_get_eigrp(vty, vrf); if (eigrp == NULL) { vty_out(vty, " EIGRP Routing Process not enabled\n"); @@ -187,6 +212,24 @@ DEFPY (show_ip_eigrp_topology, return CMD_SUCCESS; } +static void eigrp_interface_helper(struct vty *vty, struct eigrp *eigrp, + const char *ifname, const char *detail) +{ + struct eigrp_interface *ei; + struct listnode *node; + + if (!ifname) + show_ip_eigrp_interface_header(vty, eigrp); + + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { + if (!ifname || strcmp(ei->ifp->name, ifname) == 0) { + show_ip_eigrp_interface_sub(vty, eigrp, ei); + if (detail) + show_ip_eigrp_interface_detail(vty, eigrp, ei); + } + } +} + DEFPY (show_ip_eigrp_interfaces, show_ip_eigrp_interfaces_cmd, "show ip eigrp [vrf NAME] interfaces [IFNAME] [detail]$detail", @@ -198,28 +241,52 @@ DEFPY (show_ip_eigrp_interfaces, "Interface name to look at\n" "Detailed information\n") { - struct eigrp_interface *ei; struct eigrp *eigrp; - struct listnode *node; - eigrp = eigrp_vty_get_eigrp(vty, vrf); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; + if (vrf && strncmp(vrf, "all", sizeof("all")) == 0) { + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + eigrp = eigrp_lookup(vrf->vrf_id); + if (!eigrp) + continue; + + vty_out(vty, "VRF %s:\n", vrf->name); + + eigrp_interface_helper(vty, eigrp, ifname, detail); + } + } else { + eigrp = eigrp_vty_get_eigrp(vty, vrf); + if (eigrp == NULL) { + vty_out(vty, "EIGRP Routing Process not enabled\n"); + return CMD_SUCCESS; + } + + eigrp_interface_helper(vty, eigrp, ifname, detail); } - if (!ifname) - show_ip_eigrp_interface_header(vty, eigrp); + + return CMD_SUCCESS; +} + +static void eigrp_neighbors_helper(struct vty *vty, struct eigrp *eigrp, + const char *ifname, const char *detail) +{ + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + + show_ip_eigrp_neighbor_header(vty, eigrp); for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { if (!ifname || strcmp(ei->ifp->name, ifname) == 0) { - show_ip_eigrp_interface_sub(vty, eigrp, ei); - if (detail) - show_ip_eigrp_interface_detail(vty, eigrp, ei); + for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) { + if (detail || (nbr->state == EIGRP_NEIGHBOR_UP)) + show_ip_eigrp_neighbor_sub(vty, nbr, + !!detail); + } } } - - return CMD_SUCCESS; } DEFPY (show_ip_eigrp_neighbors, @@ -234,26 +301,27 @@ DEFPY (show_ip_eigrp_neighbors, "Detailed Information\n") { struct eigrp *eigrp; - struct eigrp_interface *ei; - struct listnode *node, *node2, *nnode2; - struct eigrp_neighbor *nbr; - eigrp = eigrp_vty_get_eigrp(vty, vrf); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } + if (vrf && strncmp(vrf, "all", sizeof("all")) == 0) { + struct vrf *vrf; - show_ip_eigrp_neighbor_header(vty, eigrp); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + eigrp = eigrp_lookup(vrf->vrf_id); + if (!eigrp) + continue; - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - if (!ifname || strcmp(ei->ifp->name, ifname) == 0) { - for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) { - if (detail || (nbr->state == EIGRP_NEIGHBOR_UP)) - show_ip_eigrp_neighbor_sub(vty, nbr, - !!detail); - } + vty_out(vty, "VRF %s:\n", vrf->name); + + eigrp_neighbors_helper(vty, eigrp, ifname, detail); + } + } else { + eigrp = eigrp_vty_get_eigrp(vty, vrf); + if (eigrp == NULL) { + vty_out(vty, " EIGRP Routing Process not enabled\n"); + return CMD_SUCCESS; } + + eigrp_neighbors_helper(vty, eigrp, ifname, detail); } return CMD_SUCCESS; @@ -188,7 +188,9 @@ void if_destroy_via_zapi(struct interface *ifp) if (ifp_master.destroy_hook) (*ifp_master.destroy_hook)(ifp); + ifp->oldifindex = ifp->ifindex; if_set_index(ifp, IFINDEX_INTERNAL); + if (!ifp->configured) if_delete(&ifp); } @@ -224,6 +224,8 @@ struct interface { not work as expected. */ ifindex_t ifindex; + ifindex_t oldifindex; + /* * ifindex of parent interface, if any */ diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 8ae001e42a..687cac4062 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -940,6 +940,12 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nhg_hooks.add_nexthop(nhgc, nh); } + if (intf) { + struct interface *ifp = if_lookup_by_name_all_vrf(intf); + + if (ifp) + ifp->configured = true; + } return CMD_SUCCESS; } @@ -952,24 +958,29 @@ static struct cmd_node nexthop_group_node = { .config_write = nexthop_group_write, }; -void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh) +void nexthop_group_write_nexthop_simple(struct vty *vty, + const struct nexthop *nh, + char *altifname) { char buf[100]; - struct vrf *vrf; - int i; + char *ifname; vty_out(vty, "nexthop "); + if (altifname) + ifname = altifname; + else + ifname = (char *)ifindex2ifname(nh->ifindex, nh->vrf_id); + switch (nh->type) { case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id)); + vty_out(vty, "%s", ifname); break; case NEXTHOP_TYPE_IPV4: vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4)); break; case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4), - ifindex2ifname(nh->ifindex, nh->vrf_id)); + vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4), ifname); break; case NEXTHOP_TYPE_IPV6: vty_out(vty, "%s", @@ -978,11 +989,19 @@ void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh) case NEXTHOP_TYPE_IPV6_IFINDEX: vty_out(vty, "%s %s", inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)), - ifindex2ifname(nh->ifindex, nh->vrf_id)); + ifname); break; case NEXTHOP_TYPE_BLACKHOLE: break; } +} + +void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh) +{ + struct vrf *vrf; + int i; + + nexthop_group_write_nexthop_simple(vty, nh, NULL); if (nh->vrf_id != VRF_DEFAULT) { vrf = vrf_lookup_by_id(nh->vrf_id); @@ -1229,6 +1248,7 @@ void nexthop_group_interface_state_change(struct interface *ifp, if (ifp->ifindex != nhop.ifindex) continue; + ifp->configured = true; nh = nexthop_new(); memcpy(nh, &nhop, sizeof(nhop)); diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 0b5ac91bb2..5f7bde0def 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -135,6 +135,9 @@ extern bool nexthop_group_equal(const struct nexthop_group *nhg1, extern struct nexthop_group_cmd *nhgc_find(const char *name); +extern void nexthop_group_write_nexthop_simple(struct vty *vty, + const struct nexthop *nh, + char *altifname); extern void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh); diff --git a/lib/zclient.c b/lib/zclient.c index 6b5f3e349a..b842e7c31b 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2068,7 +2068,7 @@ static void zebra_interface_if_set_value(struct stream *s, uint8_t link_params_status = 0; ifindex_t old_ifindex, new_ifindex; - old_ifindex = ifp->ifindex; + old_ifindex = ifp->oldifindex; /* Read interface's index. */ STREAM_GETL(s, new_ifindex); if_set_index(ifp, new_ifindex); diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 6d09d91c5d..f5e393a13c 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -68,12 +68,6 @@ static void ospf_spf_set_reason(ospf_spf_reason_t reason) } static void ospf_vertex_free(void *); -/* - * List of allocated vertices, to simplify cleanup of SPF. - * Not thread-safe obviously. If it ever needs to be, it'd have to be - * dynamically allocated at begin of ospf_spf_calculate - */ -static struct list vertex_list = {.del = ospf_vertex_free}; /* * Heap related functions, for the managment of the candidates, to @@ -184,7 +178,8 @@ static int vertex_parent_cmp(void *aa, void *bb) return IPV4_ADDR_CMP(&a->nexthop->router, &b->nexthop->router); } -static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa) +static struct vertex *ospf_vertex_new(struct ospf_area *area, + struct ospf_lsa *lsa) { struct vertex *new; @@ -202,7 +197,7 @@ static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa) lsa->stat = new; - listnode_add(&vertex_list, new); + listnode_add(area->spf_vertex_list, new); if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: Created %s vertex %s", __func__, @@ -292,12 +287,18 @@ static void ospf_vertex_add_parent(struct vertex *v) static void ospf_spf_init(struct ospf_area *area, struct ospf_lsa *root_lsa, bool is_dry_run, bool is_root_node) { + struct list *vertex_list; struct vertex *v; - /* Create root node. */ - v = ospf_vertex_new(root_lsa); + /* Create vertex list */ + vertex_list = list_new(); + vertex_list->del = ospf_vertex_free; + area->spf_vertex_list = vertex_list; + /* Create root node. */ + v = ospf_vertex_new(area, root_lsa); area->spf = v; + area->spf_dry_run = is_dry_run; area->spf_root_node = is_root_node; @@ -956,7 +957,7 @@ static void ospf_spf_next(struct vertex *v, struct ospf_area *area, /* Is there already vertex W in candidate list? */ if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) { /* prepare vertex W. */ - w = ospf_vertex_new(w_lsa); + w = ospf_vertex_new(area, w_lsa); /* Calculate nexthop to W. */ if (ospf_nexthop_calculation(area, v, w, l, distance, @@ -1146,6 +1147,19 @@ void ospf_rtrs_free(struct route_table *rtrs) route_table_finish(rtrs); } +void ospf_spf_cleanup(struct vertex *spf, struct list *vertex_list) +{ + /* + * Free nexthop information, canonical versions of which are + * attached the first level of router vertices attached to the + * root vertex, see ospf_nexthop_calculation. + */ + ospf_canonical_nexthops_free(spf); + + /* Free SPF vertices list with deconstructor ospf_vertex_free. */ + list_delete(&vertex_list); +} + #if 0 static void ospf_rtrs_print (struct route_table *rtrs) @@ -1311,20 +1325,8 @@ void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa, mtype_stats_alloc(MTYPE_OSPF_VERTEX)); /* If this is a dry run then keep the SPF data in place */ - if (!area->spf_dry_run) { - /* - * Free nexthop information, canonical versions of which are - * attached the first level of router vertices attached to the - * root vertex, see ospf_nexthop_calculation. - */ - ospf_canonical_nexthops_free(area->spf); - - /* - * Free SPF vertices, but not the list. List has - * ospf_vertex_free as deconstructor. - */ - list_delete_all_node(&vertex_list); - } + if (!area->spf_dry_run) + ospf_spf_cleanup(area->spf, area->spf_vertex_list); } int ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table, diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h index 0371146420..2dc0f8b886 100644 --- a/ospfd/ospf_spf.h +++ b/ospfd/ospf_spf.h @@ -82,6 +82,7 @@ extern int ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_rtrs, bool is_dry_run, bool is_root_node); extern void ospf_rtrs_free(struct route_table *); +extern void ospf_spf_cleanup(struct vertex *spf, struct list *vertex_list); extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 8a1469469f..e5e07875e8 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -414,6 +414,8 @@ struct ospf_area { /* Shortest Path Tree. */ struct vertex *spf; + struct list *spf_vertex_list; + bool spf_dry_run; /* flag for checking if the SPF calculation is intended for the local RIB */ bool spf_root_node; /* flag for checking if the calculating node is the diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 10a75a9f54..058881cbfc 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -771,6 +771,67 @@ void pbr_map_check_nh_group_change(const char *nh_group) } } +void pbr_map_check_vrf_nh_group_change(const char *nh_group, + struct pbr_vrf *pbr_vrf, + uint32_t old_vrf_id) +{ + struct pbr_map *pbrm; + struct pbr_map_sequence *pbrms; + struct listnode *node; + + + RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { + for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { + if (pbrms->nhgrp_name) + continue; + + if (pbrms->nhg == NULL) + continue; + + if (strcmp(nh_group, pbrms->internal_nhg_name)) + continue; + + if (pbrms->nhg->nexthop == NULL) + continue; + + if (pbrms->nhg->nexthop->vrf_id != old_vrf_id) + continue; + + pbrms->nhg->nexthop->vrf_id = pbr_vrf_id(pbr_vrf); + } + } +} + +void pbr_map_check_interface_nh_group_change(const char *nh_group, + struct interface *ifp, + ifindex_t oldifindex) +{ + struct pbr_map *pbrm; + struct pbr_map_sequence *pbrms; + struct listnode *node; + + RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { + for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { + if (pbrms->nhgrp_name) + continue; + + if (pbrms->nhg == NULL) + continue; + + if (strcmp(nh_group, pbrms->internal_nhg_name)) + continue; + + if (pbrms->nhg->nexthop == NULL) + continue; + + if (pbrms->nhg->nexthop->ifindex != oldifindex) + continue; + + pbrms->nhg->nexthop->ifindex = ifp->ifindex; + } + } +} + void pbr_map_check(struct pbr_map_sequence *pbrms, bool changed) { struct pbr_map *pbrm; diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 64c090d2e8..43266f21e9 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -205,4 +205,11 @@ extern void pbr_map_install(struct pbr_map *pbrm); extern void pbr_map_policy_install(const char *name); extern void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi); + +extern void pbr_map_check_vrf_nh_group_change(const char *nh_group, + struct pbr_vrf *pbr_vrf, + uint32_t old_vrf_id); +extern void pbr_map_check_interface_nh_group_change(const char *nh_group, + struct interface *ifp, + ifindex_t oldifindex); #endif diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 31da656793..3fb3759049 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -37,7 +37,7 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups") -static struct hash *pbr_nhg_hash; +struct hash *pbr_nhg_hash; static struct hash *pbr_nhrc_hash; static uint32_t pbr_nhg_low_table; @@ -91,15 +91,15 @@ static void *pbr_nh_alloc(void *p) struct nhrc *nhrc; new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new)); - nhrc = hash_get(pbr_nhrc_hash, pnhc->nexthop, pbr_nhrc_hash_alloc); - new->nexthop = &nhrc->nexthop; + nhrc = hash_get(pbr_nhrc_hash, &pnhc->nexthop, pbr_nhrc_hash_alloc); + new->nexthop = nhrc->nexthop; /* Decremented again in pbr_nh_delete */ ++nhrc->refcount; DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra", __func__); - pbr_send_rnh(new->nexthop, true); + pbr_send_rnh(&new->nexthop, true); new->valid = false; return new; @@ -109,14 +109,14 @@ static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc) { struct nhrc *nhrc; - nhrc = hash_lookup(pbr_nhrc_hash, (*pnhc)->nexthop); + nhrc = hash_lookup(pbr_nhrc_hash, &((*pnhc)->nexthop)); if (nhrc) --nhrc->refcount; if (!nhrc || nhrc->refcount == 0) { DEBUGD(&pbr_dbg_nht, "%s: Removing nexthop from Zebra", __func__); - pbr_send_rnh((*pnhc)->nexthop, false); + pbr_send_rnh(&((*pnhc)->nexthop), false); } if (nhrc && nhrc->refcount == 0) { hash_release(pbr_nhrc_hash, nhrc); @@ -136,7 +136,7 @@ static uint32_t pbr_nh_hash_key(const void *arg) uint32_t key; const struct pbr_nexthop_cache *pbrnc = arg; - key = nexthop_hash(pbrnc->nexthop); + key = nexthop_hash(&pbrnc->nexthop); return key; } @@ -148,28 +148,28 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2) const struct pbr_nexthop_cache *pbrnc2 = (const struct pbr_nexthop_cache *)arg2; - if (pbrnc1->nexthop->vrf_id != pbrnc2->nexthop->vrf_id) + if (pbrnc1->nexthop.vrf_id != pbrnc2->nexthop.vrf_id) return false; - if (pbrnc1->nexthop->ifindex != pbrnc2->nexthop->ifindex) + if (pbrnc1->nexthop.ifindex != pbrnc2->nexthop.ifindex) return false; - if (pbrnc1->nexthop->type != pbrnc2->nexthop->type) + if (pbrnc1->nexthop.type != pbrnc2->nexthop.type) return false; - switch (pbrnc1->nexthop->type) { + switch (pbrnc1->nexthop.type) { case NEXTHOP_TYPE_IFINDEX: - return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex; + return pbrnc1->nexthop.ifindex == pbrnc2->nexthop.ifindex; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: - return pbrnc1->nexthop->gate.ipv4.s_addr - == pbrnc2->nexthop->gate.ipv4.s_addr; + return pbrnc1->nexthop.gate.ipv4.s_addr + == pbrnc2->nexthop.gate.ipv4.s_addr; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: - return !memcmp(&pbrnc1->nexthop->gate.ipv6, - &pbrnc2->nexthop->gate.ipv6, 16); + return !memcmp(&pbrnc1->nexthop.gate.ipv6, + &pbrnc2->nexthop.gate.ipv6, 16); case NEXTHOP_TYPE_BLACKHOLE: - return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type; + return pbrnc1->nexthop.bh_type == pbrnc2->nexthop.bh_type; } /* @@ -249,9 +249,8 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, pnhgc = hash_get(pbr_nhg_hash, &pnhgc_find, pbr_nhgc_alloc); /* create & insert new pnhc into pnhgc->nhh */ - pnhc_find.nexthop = (struct nexthop *)nhop; + pnhc_find.nexthop = *nhop; pnhc = hash_get(pnhgc->nhh, &pnhc_find, pbr_nh_alloc); - pnhc_find.nexthop = NULL; /* set parent pnhgc */ pnhc->parent = pnhgc; @@ -291,7 +290,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, pnhgc = hash_lookup(pbr_nhg_hash, &pnhgc_find); /* delete pnhc from pnhgc->nhh */ - pnhc_find.nexthop = (struct nexthop *)nhop; + pnhc_find.nexthop = *nhop; pnhc = hash_release(pnhgc->nhh, &pnhc_find); /* delete pnhc */ @@ -499,7 +498,7 @@ void pbr_nht_change_group(const char *name) struct pbr_nexthop_cache lookup; struct pbr_nexthop_cache *pnhc; - lookup.nexthop = nhop; + lookup.nexthop = *nhop; pnhc = hash_lookup(pnhgc->nhh, &lookup); if (!pnhc) { pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc); @@ -553,9 +552,25 @@ void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms, pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc); - lookup.nexthop = pbrms->nhg->nexthop; + lookup.nexthop = *pbrms->nhg->nexthop; pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc); pnhc->parent = pnhgc; + if (nhop->vrf_id != VRF_DEFAULT) { + struct vrf *vrf = vrf_lookup_by_id(nhop->vrf_id); + + if (vrf) + strlcpy(pnhc->vrf_name, vrf->name, + sizeof(pnhc->vrf_name)); + } + + if (nhop->ifindex != 0) { + struct interface *ifp = + if_lookup_by_index(nhop->ifindex, nhop->vrf_id); + + if (ifp) + strlcpy(pnhc->intf_name, ifp->name, + sizeof(pnhc->intf_name)); + } pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg); } @@ -574,7 +589,7 @@ static void pbr_nht_release_individual_nexthop(struct pbr_map_sequence *pbrms) nh = pbrms->nhg->nexthop; nh_type = nh->type; - lup.nexthop = nh; + lup.nexthop = *nh; pnhc = hash_lookup(pnhgc->nhh, &lup); pnhc->parent = NULL; hash_release(pnhgc->nhh, pnhc); @@ -625,7 +640,7 @@ struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name) struct pbr_nexthop_cache lookupc; struct pbr_nexthop_cache *pnhc; - lookupc.nexthop = nhop; + lookupc.nexthop = *nhop; pnhc = hash_lookup(pnhgc->nhh, &lookupc); if (!pnhc) { pnhc = hash_get(pnhgc->nhh, &lookupc, pbr_nh_alloc); @@ -689,13 +704,18 @@ bool pbr_nht_nexthop_group_valid(const char *name) struct pbr_nht_individual { struct zapi_route *nhr; struct interface *ifp; + struct pbr_vrf *pbr_vrf; + struct pbr_nexthop_cache *pnhc; + vrf_id_t old_vrf_id; - uint32_t valid; + bool valid; + + bool nhr_matched; }; static bool pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, - const struct pbr_nht_individual *pnhi) + struct pbr_nht_individual *pnhi) { bool is_valid = pnhc->valid; @@ -704,25 +724,26 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, switch (pnhi->nhr->prefix.family) { case AF_INET: - if (pnhc->nexthop->gate.ipv4.s_addr + if (pnhc->nexthop.gate.ipv4.s_addr != pnhi->nhr->prefix.u.prefix4.s_addr) goto done; /* Unrelated change */ break; case AF_INET6: - if (memcmp(&pnhc->nexthop->gate.ipv6, + if (memcmp(&pnhc->nexthop.gate.ipv6, &pnhi->nhr->prefix.u.prefix6, 16) != 0) goto done; /* Unrelated change */ break; } + pnhi->nhr_matched = true; if (!pnhi->nhr->nexthop_num) { is_valid = false; goto done; } - if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - || pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { + if (pnhc->nexthop.type == NEXTHOP_TYPE_IPV4_IFINDEX + || pnhc->nexthop.type == NEXTHOP_TYPE_IPV6_IFINDEX) { /* GATEWAY_IFINDEX type shouldn't resolve to group */ if (pnhi->nhr->nexthop_num > 1) { @@ -733,7 +754,7 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, /* If whatever we resolved to wasn't on the interface we * specified. (i.e. not a connected route), its invalid. */ - if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop->ifindex) { + if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop.ifindex) { is_valid = false; goto done; } @@ -747,18 +768,20 @@ done: return pnhc->valid; } -static bool pbr_nht_individual_nexthop_interface_update( - struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi) +static bool +pbr_nht_individual_nexthop_interface_update(struct pbr_nexthop_cache *pnhc, + struct pbr_nht_individual *pnhi) { bool is_valid = pnhc->valid; if (!pnhi->ifp) /* It doesn't care about non-interface updates */ goto done; - if (pnhc->nexthop->ifindex + if (pnhc->nexthop.ifindex != pnhi->ifp->ifindex) /* Un-related interface */ goto done; + pnhi->nhr_matched = true; is_valid = !!if_is_up(pnhi->ifp); done: @@ -773,18 +796,17 @@ done: * If the update is un-related, the subroutines shoud just return their cached * valid state. */ -static void -pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc, - const struct pbr_nht_individual *pnhi) +static void pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc, + struct pbr_nht_individual *pnhi) { assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */ - switch (pnhc->nexthop->type) { + switch (pnhc->nexthop.type) { case NEXTHOP_TYPE_IFINDEX: pbr_nht_individual_nexthop_interface_update(pnhc, pnhi); break; case NEXTHOP_TYPE_IPV6_IFINDEX: - if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop->gate.ipv6)) { + if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop.gate.ipv6)) { pbr_nht_individual_nexthop_interface_update(pnhc, pnhi); break; } @@ -817,7 +839,7 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b, pnhc->valid); if (pnhc->valid) - pnhi->valid += 1; + pnhi->valid = true; } static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b, @@ -827,7 +849,7 @@ static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b, struct nexthop_group *nhg = data; struct nexthop *nh = NULL; - copy_nexthops(&nh, pnhc->nexthop, NULL); + copy_nexthops(&nh, &pnhc->nexthop, NULL); _nexthop_add(&nhg->nexthop, nh); } @@ -849,10 +871,14 @@ static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data) old_valid = pnhgc->valid; pnhi.nhr = (struct zapi_route *)data; - pnhi.valid = 0; + pnhi.valid = false; + pnhi.nhr_matched = false; hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup, &pnhi); + if (!pnhi.nhr_matched) + return; + /* * If any of the specified nexthops are valid we are valid */ @@ -877,6 +903,178 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr) hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr); } +struct nhrc_vrf_info { + struct pbr_vrf *pbr_vrf; + uint32_t old_vrf_id; + struct nhrc *nhrc; +}; + +static int pbr_nht_nhrc_vrf_change(struct hash_bucket *b, void *data) +{ + struct nhrc *nhrc = b->data; + struct nhrc_vrf_info *nhrcvi = data; + + if (nhrc->nexthop.vrf_id == nhrcvi->old_vrf_id) { + nhrcvi->nhrc = nhrc; + return HASHWALK_ABORT; + } + + return HASHWALK_CONTINUE; +} + +static int pbr_nht_individual_nexthop_vrf_handle(struct hash_bucket *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct pbr_nht_individual *pnhi = data; + + if (pnhc->looked_at == true) + return HASHWALK_CONTINUE; + + if (pnhc->nexthop.vrf_id == VRF_DEFAULT) + return HASHWALK_CONTINUE; + + if (strncmp(pnhc->vrf_name, pbr_vrf_name(pnhi->pbr_vrf), + sizeof(pnhc->vrf_name)) + == 0) { + pnhi->pnhc = pnhc; + + if (pnhc->nexthop.vrf_id != pbr_vrf_id(pnhi->pbr_vrf)) { + struct nhrc_vrf_info nhrcvi; + + memset(&nhrcvi, 0, sizeof(nhrcvi)); + nhrcvi.pbr_vrf = pnhi->pbr_vrf; + nhrcvi.old_vrf_id = pnhc->nexthop.vrf_id; + + pnhi->nhr_matched = true; + pnhi->old_vrf_id = pnhc->nexthop.vrf_id; + + do { + nhrcvi.nhrc = NULL; + hash_walk(pbr_nhrc_hash, + pbr_nht_nhrc_vrf_change, &nhrcvi); + if (nhrcvi.nhrc) { + hash_release(pbr_nhrc_hash, + nhrcvi.nhrc); + nhrcvi.nhrc->nexthop.vrf_id = + pbr_vrf_id(pnhi->pbr_vrf); + hash_get(pbr_nhrc_hash, nhrcvi.nhrc, + hash_alloc_intern); + pbr_send_rnh(&nhrcvi.nhrc->nexthop, true); + } + } while (nhrcvi.nhrc); + } + + pnhc->looked_at = true; + return HASHWALK_ABORT; + } + + return HASHWALK_CONTINUE; +} + +static void pbr_nht_clear_looked_at(struct hash_bucket *b, void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + + pnhc->looked_at = false; +} + +static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data) +{ + struct pbr_nexthop_group_cache *pnhgc = b->data; + struct pbr_vrf *pbr_vrf = data; + struct pbr_nht_individual pnhi = {}; + + zlog_debug("pnhgc iterating"); + hash_iterate(pnhgc->nhh, pbr_nht_clear_looked_at, NULL); + memset(&pnhi, 0, sizeof(pnhi)); + pnhi.pbr_vrf = pbr_vrf; + do { + struct pbr_nexthop_cache *pnhc; + + pnhi.pnhc = NULL; + hash_walk(pnhgc->nhh, pbr_nht_individual_nexthop_vrf_handle, + &pnhi); + + if (!pnhi.pnhc) + continue; + + pnhc = pnhi.pnhc; + pnhc->nexthop.vrf_id = pnhi.old_vrf_id; + pnhi.pnhc = hash_release(pnhgc->nhh, pnhi.pnhc); + if (pnhi.pnhc) { + pnhi.pnhc->nexthop.vrf_id = pbr_vrf_id(pbr_vrf); + + hash_get(pnhgc->nhh, pnhi.pnhc, hash_alloc_intern); + } else + pnhc->nexthop.vrf_id = pbr_vrf_id(pbr_vrf); + + pbr_map_check_vrf_nh_group_change(pnhgc->name, pbr_vrf, + pnhi.old_vrf_id); + } while (pnhi.pnhc); +} + +void pbr_nht_vrf_update(struct pbr_vrf *pbr_vrf) +{ + hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_vrf_handle, pbr_vrf); +} + +static void pbr_nht_individual_nexthop_interface_handle(struct hash_bucket *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct pbr_nht_individual *pnhi = data; + + if (pnhc->nexthop.ifindex == 0) + return; + + if ((strncmp(pnhc->intf_name, pnhi->ifp->name, sizeof(pnhc->intf_name)) + == 0) + && pnhc->nexthop.ifindex != pnhi->ifp->ifindex) + pnhi->pnhc = pnhc; +} + +static void pbr_nht_nexthop_interface_handle(struct hash_bucket *b, void *data) +{ + struct pbr_nexthop_group_cache *pnhgc = b->data; + struct interface *ifp = data; + struct pbr_nht_individual pnhi = {}; + struct nhrc *nhrc; + uint32_t old_ifindex; + + do { + memset(&pnhi, 0, sizeof(pnhi)); + pnhi.ifp = ifp; + hash_iterate(pnhgc->nhh, + pbr_nht_individual_nexthop_interface_handle, + &pnhi); + + if (!pnhi.pnhc) + continue; + + pnhi.pnhc = hash_release(pnhgc->nhh, pnhi.pnhc); + old_ifindex = pnhi.pnhc->nexthop.ifindex; + + nhrc = hash_lookup(pbr_nhrc_hash, &pnhi.pnhc->nexthop); + if (nhrc) { + hash_release(pbr_nhrc_hash, nhrc); + nhrc->nexthop.ifindex = ifp->ifindex; + hash_get(pbr_nhrc_hash, nhrc, hash_alloc_intern); + } + pnhi.pnhc->nexthop.ifindex = ifp->ifindex; + + hash_get(pnhgc->nhh, pnhi.pnhc, hash_alloc_intern); + + pbr_map_check_interface_nh_group_change(pnhgc->name, ifp, + old_ifindex); + } while (pnhi.pnhc); +} + +void pbr_nht_interface_update(struct interface *ifp) +{ + hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_handle, ifp); +} + static void pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b, void *data) @@ -893,7 +1091,7 @@ pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b, old_valid, pnhc->valid); if (pnhc->valid) - pnhi->valid += 1; + pnhi->valid = true; } static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b, @@ -906,14 +1104,14 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b, old_valid = pnhgc->valid; pnhi.ifp = data; - pnhi.valid = 0; + pnhi.valid = false; hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_interface_update_lookup, &pnhi); /* * If any of the specified nexthops are valid we are valid */ - pnhgc->valid = !!pnhi.valid; + pnhgc->valid = pnhi.valid; if (old_valid != pnhgc->valid) pbr_map_check_nh_group_change(pnhgc->name); @@ -1036,7 +1234,7 @@ static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data) struct vty *vty = data; vty_out(vty, "\tValid: %d ", pnhc->valid); - nexthop_group_write_nexthop(vty, pnhc->nexthop); + nexthop_group_write_nexthop(vty, &pnhc->nexthop); } static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data) @@ -1046,7 +1244,7 @@ static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data) json_object *this_hop; this_hop = json_object_new_object(); - nexthop_group_json_nexthop(this_hop, pnhc->nexthop); + nexthop_group_json_nexthop(this_hop, &pnhc->nexthop); json_object_boolean_add(this_hop, "valid", pnhc->valid); json_object_array_add(all_hops, this_hop); diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index cbcf71d2f5..6346795215 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -28,6 +28,8 @@ #define PBR_NHC_NAMELEN PBR_MAP_NAMELEN + 10 +extern struct hash *pbr_nhg_hash; + struct pbr_nexthop_group_cache { char name[PBR_NHC_NAMELEN]; @@ -46,9 +48,14 @@ struct pbr_nexthop_group_cache { struct pbr_nexthop_cache { struct pbr_nexthop_group_cache *parent; - struct nexthop *nexthop; + char vrf_name[VRF_NAMSIZ + 1]; + char intf_name[INTERFACE_NAMSIZ + 1]; + + struct nexthop nexthop; + bool looked_at; bool valid; + bool nhr_matched; }; extern void pbr_nht_write_table_range(struct vty *vty); @@ -126,4 +133,7 @@ extern void pbr_nht_nexthop_update(struct zapi_route *nhr); extern void pbr_nht_nexthop_interface_update(struct interface *ifp); extern void pbr_nht_init(void); + +extern void pbr_nht_vrf_update(struct pbr_vrf *pbr_vrf); +extern void pbr_nht_interface_update(struct interface *ifp); #endif diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c index d5a2bd0fef..389e5e8be0 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -25,6 +25,7 @@ #include "pbr_memory.h" #include "pbr_map.h" #include "pbr_debug.h" +#include "pbr_nht.h" DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF") @@ -59,6 +60,7 @@ static int pbr_vrf_enable(struct vrf *vrf) { DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name); + pbr_nht_vrf_update(vrf->info); pbr_map_vrf_update(vrf->info); return 0; diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index a73d885ea6..9f966f617f 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -618,6 +618,33 @@ DEFPY (show_pbr, return CMD_SUCCESS; } +static void +pbrms_nexthop_group_write_individual_nexthop( + struct vty *vty, const struct pbr_map_sequence *pbrms) +{ + struct pbr_nexthop_group_cache find; + struct pbr_nexthop_group_cache *pnhgc; + struct pbr_nexthop_cache lookup; + struct pbr_nexthop_cache *pnhc; + + memset(&find, 0, sizeof(find)); + strlcpy(find.name, pbrms->internal_nhg_name, sizeof(find.name)); + + pnhgc = hash_lookup(pbr_nhg_hash, &find); + assert(pnhgc); + + lookup.nexthop = *pbrms->nhg->nexthop; + pnhc = hash_lookup(pnhgc->nhh, &lookup); + + nexthop_group_write_nexthop_simple( + vty, pbrms->nhg->nexthop, + pnhc->nexthop.ifindex != 0 ? pnhc->intf_name : NULL); + if (pnhc->nexthop.vrf_id != VRF_DEFAULT) + vty_out(vty, " nexthop-vrf %s", pnhc->vrf_name); + + vty_out(vty, "\n"); +} + static void vty_show_pbrms(struct vty *vty, const struct pbr_map_sequence *pbrms, bool detail) { @@ -670,7 +697,7 @@ static void vty_show_pbrms(struct vty *vty, } else if (pbrms->nhg) { vty_out(vty, " "); - nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop); + pbrms_nexthop_group_write_individual_nexthop(vty, pbrms); if (detail) vty_out(vty, " Installed: %u(%d) Tableid: %d\n", @@ -1065,7 +1092,7 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, if (pbrms->nhg) { vty_out(vty, " set "); - nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop); + pbrms_nexthop_group_write_individual_nexthop(vty, pbrms); } vty_out(vty, "!\n"); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index d0099a46e3..a7420974a9 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -67,6 +67,7 @@ int pbr_ifp_create(struct interface *ifp) if (!ifp->info) pbr_if_new(ifp); + pbr_nht_interface_update(ifp); /* Update nexthops tracked from a `set nexthop` command */ pbr_nht_nexthop_interface_update(ifp); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 16c94b7482..ad0d4bf56b 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1453,6 +1453,15 @@ void kernel_init(struct zebra_ns *zns) if (ret < 0) zlog_notice("Registration for extended dp ACK failed : %d %s", errno, safe_strerror(errno)); + + /* + * Trim off the payload of the original netlink message in the + * acknowledgment. This option is available since Linux 4.2, so if + * setsockopt fails, ignore the error. + */ + one = 1; + ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK, + &one, sizeof(one)); #endif /* Register kernel socket. */ @@ -1469,8 +1478,11 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_dplane.name, safe_strerror(errno), errno); /* Set receive buffer size if it's set from command line */ - if (nl_rcvbufsize) + if (nl_rcvbufsize) { netlink_recvbuf(&zns->netlink, nl_rcvbufsize); + netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane, nl_rcvbufsize); + } netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid, |
