diff options
| -rw-r--r-- | bgpd/bgp_evpn.c | 67 | ||||
| -rw-r--r-- | bgpd/bgp_main.c | 2 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 11 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 259 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 6 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 3 | ||||
| -rw-r--r-- | doc/OSPF-SR.rst | 23 | ||||
| -rw-r--r-- | doc/ospfd.texi | 7 | ||||
| -rw-r--r-- | lib/command.c | 3 | ||||
| -rw-r--r-- | lib/netns_linux.c | 9 | ||||
| -rw-r--r-- | lib/zclient.c | 4 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.c | 267 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.h | 3 | ||||
| -rw-r--r-- | ospf6d/ospf6_route.c | 26 | ||||
| -rw-r--r-- | ospf6d/ospf6_top.c | 27 | ||||
| -rw-r--r-- | ospfd/ospf_main.c | 2 | ||||
| -rw-r--r-- | ospfd/ospf_sr.c | 264 | ||||
| -rw-r--r-- | ospfd/ospfd.c | 1 | ||||
| -rw-r--r-- | tests/.gitignore | 4 | ||||
| -rw-r--r-- | tests/lib/test_ringbuf.py | 4 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 2 | ||||
| -rw-r--r-- | vtysh/vtysh_config.c | 7 | ||||
| -rw-r--r-- | zebra/zebra_rnh.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 57 | ||||
| -rw-r--r-- | zebra/zserv.c | 10 |
25 files changed, 657 insertions, 415 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a8ee14c72e..e5863e4980 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1760,8 +1760,10 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) } /* - * There is a tunnel endpoint IP address change for this VNI, - * need to re-advertise routes with the new nexthop. + * There is a tunnel endpoint IP address change for this VNI, delete + * prior type-3 route (if needed) and update. + * Note: Route re-advertisement happens elsewhere after other processing + * other changes. */ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, struct in_addr originator_ip) @@ -1789,7 +1791,7 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, /* Update the tunnel IP and re-advertise all routes for this VNI. */ vpn->originator_ip = originator_ip; - return update_routes_for_vni(bgp, vpn); + return 0; } /* @@ -3245,15 +3247,25 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, { struct bgp_table *table = NULL; struct bgp_node *rn = NULL; + struct bgp_info *ri; /* Bail out early if we don't have to advertise type-5 routes. */ if (!advertise_type5_routes(bgp_vrf, afi)) return; table = bgp_vrf->rib[afi][safi]; - for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) - bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi); - + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + /* Only care about "selected" routes - non-imported. */ + /* TODO: Support for AddPath for EVPN. */ + for (ri = rn->info; ri; ri = ri->next) { + if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) && + (!ri->extra || !ri->extra->parent)) { + bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, + afi, safi); + break; + } + } + } } /* @@ -3274,10 +3286,6 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, if (!advertise_type5_routes(bgp_vrf, afi)) return; - /* only advertise subnet routes as type-5 */ - if (is_host_route(p)) - return; - build_type5_prefix_from_ip_prefix(&evp, p); ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr); if (ret) @@ -3305,11 +3313,12 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { /* Need to identify the "selected" route entry to use its - * attribute. + * attribute. Also, we only consider "non-imported" routes. * TODO: Support for AddPath for EVPN. */ for (ri = rn->info; ri; ri = ri->next) { - if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) { + if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) && + (!ri->extra || !ri->extra->parent)) { /* apply the route-map */ if (bgp_vrf->adv_cmd_rmap[afi][safi].map) { @@ -3322,7 +3331,6 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, if (ret == RMAP_DENYMATCH) continue; } - bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p, ri->attr, afi, safi); @@ -4449,8 +4457,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) } /* - * Handle add (or update) of a local VNI. The only VNI change we care - * about is change to local-tunnel-ip. + * Handle add (or update) of a local VNI. The VNI changes we care + * about are for the local-tunnel-ip and the (tenant) VRF. */ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip, @@ -4468,24 +4476,31 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, vpn = bgp_evpn_lookup_vni(bgp, vni); if (vpn) { - /* update tenant_vrf_id if required */ + if (is_vni_live(vpn) + && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip) + && vpn->tenant_vrf_id == tenant_vrf_id) + /* Probably some other param has changed that we don't + * care about. */ + return 0; + + /* Update tenant_vrf_id if it has changed. */ if (vpn->tenant_vrf_id != tenant_vrf_id) { bgpevpn_unlink_from_l3vni(vpn); vpn->tenant_vrf_id = tenant_vrf_id; bgpevpn_link_to_l3vni(vpn); - - /* update all routes with new export RT for VRFs */ - update_routes_for_vni(bgp, vpn); } - if (is_vni_live(vpn) - && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) - /* Probably some other param has changed that we don't - * care about. */ - return 0; + /* If tunnel endpoint IP has changed, update (and delete prior + * type-3 route, if needed.) + */ + if (!IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) + handle_tunnel_ip_change(bgp, vpn, originator_ip); - /* Local tunnel endpoint IP address has changed */ - handle_tunnel_ip_change(bgp, vpn, originator_ip); + /* Update all routes with new endpoint IP and/or export RT + * for VRFs + */ + if (is_vni_live(vpn)) + update_routes_for_vni(bgp, vpn); } /* Create or update as appropriate. */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 82c74e4afa..30b7afff92 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -106,7 +106,7 @@ static int retain_mode = 0; /* privileges */ static zebra_capabilities_t _caps_p[] = { - ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, + ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN }; struct zebra_privs_t bgpd_privs = { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 20bf9635a3..3dfc446b2c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2228,10 +2228,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { - if (new_select) - bgp_evpn_advertise_type5_route( - bgp, &rn->p, new_select->attr, afi, safi); - else if (old_select) + if (new_select && + (!new_select->extra || !new_select->extra->parent)) + bgp_evpn_advertise_type5_route(bgp, &rn->p, + new_select->attr, + afi, safi); + else if (old_select && + (!old_select->extra || !old_select->extra->parent)) bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 2f60871e88..c503a91be2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -833,7 +833,7 @@ DEFUN_NOSH (router_bgp, if (listcount(bm->bgp) > 1) { vty_out(vty, - "%% Multiple BGP processes are configured\n"); + "%% Please specify ASN and VRF\n"); return CMD_WARNING_CONFIG_FAILED; } } @@ -909,7 +909,7 @@ DEFUN (no_router_bgp, if (listcount(bm->bgp) > 1) { vty_out(vty, - "%% Multiple BGP processes are configured\n"); + "%% Please specify ASN and VRF\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -10314,227 +10314,43 @@ static void show_bgp_updgrps_adj_info_aux(struct vty *vty, const char *name, } } -DEFUN (show_ip_bgp_updgrps_adj, - show_ip_bgp_updgrps_adj_cmd, - "show [ip] bgp update-groups <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - "Detailed info about dynamic update groups\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_type = 4; - show_bgp_updgrps_adj_info_aux(vty, NULL, AFI_IP, SAFI_UNICAST, - argv[idx_type]->arg, 0); - return CMD_SUCCESS; -} - -DEFUN (show_ip_bgp_instance_updgrps_adj, - show_ip_bgp_instance_updgrps_adj_cmd, - "show [ip] bgp <view|vrf> VIEWVRFNAME update-groups <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - "Detailed info about dynamic update groups\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_word = 4; - int idx_type = 6; - show_bgp_updgrps_adj_info_aux(vty, argv[idx_word]->arg, AFI_IP, - SAFI_UNICAST, argv[idx_type]->arg, 0); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_updgrps_afi_adj, - show_bgp_updgrps_afi_adj_cmd, - "show [ip] bgp "BGP_AFI_SAFI_CMD_STR" update-groups <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - BGP_AFI_SAFI_HELP_STR - "Detailed info about dynamic update groups\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_afi = 2; - int idx_safi = 3; - int idx_type = 5; - show_bgp_updgrps_adj_info_aux( - vty, NULL, bgp_vty_afi_from_str(argv[idx_afi]->text), - bgp_vty_safi_from_str(argv[idx_safi]->text), - argv[idx_type]->arg, 0); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_updgrps_adj, - show_bgp_updgrps_adj_cmd, - "show [ip] bgp update-groups <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - "Detailed info about dynamic update groups\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_type = 3; - show_bgp_updgrps_adj_info_aux(vty, NULL, AFI_IP6, SAFI_UNICAST, - argv[idx_type]->arg, 0); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_instance_updgrps_adj, - show_bgp_instance_updgrps_adj_cmd, - "show [ip] bgp <view|vrf> VIEWVRFNAME update-groups <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - "Detailed info about dynamic update groups\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_word = 3; - int idx_type = 5; - show_bgp_updgrps_adj_info_aux(vty, argv[idx_word]->arg, AFI_IP6, - SAFI_UNICAST, argv[idx_type]->arg, 0); - return CMD_SUCCESS; -} - -DEFUN (show_ip_bgp_updgrps_adj_s, - show_ip_bgp_updgrps_adj_s_cmd, - "show [ip] bgp update-groups SUBGROUP-ID <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - "Detailed info about dynamic update groups\n" - "Specific subgroup to display info for\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") +DEFPY(show_ip_bgp_instance_updgrps_adj_s, + show_ip_bgp_instance_updgrps_adj_s_cmd, + "show [ip]$ip bgp [<view|vrf> VIEWVRFNAME$vrf] [<ipv4|ipv6>$afi <unicast|multicast|vpn>$safi] update-groups [SUBGROUP-ID]$sgid <advertise-queue|advertised-routes|packet-queue>$rtq", + SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR + BGP_SAFI_HELP_STR + "Detailed info about dynamic update groups\n" + "Specific subgroup to display info for\n" + "Advertisement queue\n" + "Announced routes\n" + "Packet queue\n") { - int idx_subgroup_id = 4; - int idx_type = 5; - uint64_t subgrp_id; - - subgrp_id = strtoull(argv[idx_subgroup_id]->arg, NULL, 10); - - show_bgp_updgrps_adj_info_aux(vty, NULL, AFI_IP, SAFI_UNICAST, - argv[idx_type]->arg, subgrp_id); - return CMD_SUCCESS; -} - -DEFUN (show_ip_bgp_instance_updgrps_adj_s, - show_ip_bgp_instance_updgrps_adj_s_cmd, - "show [ip] bgp <view|vrf> VIEWVRFNAME update-groups SUBGROUP-ID <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - "Detailed info about dynamic update groups\n" - "Specific subgroup to display info for\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_vrf = 4; - int idx_subgroup_id = 6; - int idx_type = 7; - uint64_t subgrp_id; - - subgrp_id = strtoull(argv[idx_subgroup_id]->arg, NULL, 10); - - show_bgp_updgrps_adj_info_aux(vty, argv[idx_vrf]->arg, AFI_IP, - SAFI_UNICAST, argv[idx_type]->arg, - subgrp_id); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_updgrps_afi_adj_s, - show_bgp_updgrps_afi_adj_s_cmd, - "show [ip] bgp "BGP_AFI_SAFI_CMD_STR" update-groups SUBGROUP-ID <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - BGP_AFI_SAFI_HELP_STR - "Detailed info about dynamic update groups\n" - "Specific subgroup to display info for\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_afi = 2; - int idx_safi = 3; - int idx_subgroup_id = 5; - int idx_type = 6; - uint64_t subgrp_id; - - subgrp_id = strtoull(argv[idx_subgroup_id]->arg, NULL, 10); - - show_bgp_updgrps_adj_info_aux( - vty, NULL, bgp_vty_afi_from_str(argv[idx_afi]->text), - bgp_vty_safi_from_str(argv[idx_safi]->text), - argv[idx_type]->arg, subgrp_id); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_updgrps_adj_s, - show_bgp_updgrps_adj_s_cmd, - "show [ip] bgp update-groups SUBGROUP-ID <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - "Detailed info about dynamic update groups\n" - "Specific subgroup to display info for\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_subgroup_id = 3; - int idx_type = 4; - uint64_t subgrp_id; - - subgrp_id = strtoull(argv[idx_subgroup_id]->arg, NULL, 10); - - show_bgp_updgrps_adj_info_aux(vty, NULL, AFI_IP6, SAFI_UNICAST, - argv[idx_type]->arg, subgrp_id); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_instance_updgrps_adj_s, - show_bgp_instance_updgrps_adj_s_cmd, - "show [ip] bgp <view|vrf> VIEWVRFNAME update-groups SUBGROUP-ID <advertise-queue|advertised-routes|packet-queue>", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - "Detailed info about dynamic update groups\n" - "Specific subgroup to display info for\n" - "Advertisement queue\n" - "Announced routes\n" - "Packet queue\n") -{ - int idx_vrf = 3; - int idx_subgroup_id = 5; - int idx_type = 6; - uint64_t subgrp_id; + uint64_t subgrp_id = 0; + afi_t afiz; + safi_t safiz; + if (sgid) + subgrp_id = strtoull(sgid, NULL, 10); + + if (!ip && !afi) + afiz = AFI_IP6; + if (!ip && afi) + afiz = bgp_vty_afi_from_str(afi); + if (ip && !afi) + afiz = AFI_IP; + if (ip && afi) { + afiz = bgp_vty_afi_from_str(afi); + if (afiz != AFI_IP) + vty_out(vty, + "%% Cannot specify both 'ip' and 'ipv6'\n"); + return CMD_WARNING; + } - subgrp_id = strtoull(argv[idx_subgroup_id]->arg, NULL, 10); + safiz = safi ? bgp_vty_safi_from_str(safi) : SAFI_UNICAST; - show_bgp_updgrps_adj_info_aux(vty, argv[idx_vrf]->arg, AFI_IP6, - SAFI_UNICAST, argv[idx_type]->arg, - subgrp_id); + show_bgp_updgrps_adj_info_aux(vty, vrf, afiz, safiz, rtq, subgrp_id); return CMD_SUCCESS; } - static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) { struct listnode *node, *nnode; @@ -12449,19 +12265,10 @@ void bgp_vty_init(void) /* "show [ip] bgp summary" commands. */ install_element(VIEW_NODE, &show_bgp_instance_all_ipv6_updgrps_cmd); - install_element(VIEW_NODE, &show_bgp_instance_updgrps_adj_cmd); - install_element(VIEW_NODE, &show_bgp_instance_updgrps_adj_s_cmd); install_element(VIEW_NODE, &show_bgp_instance_updgrps_stats_cmd); - install_element(VIEW_NODE, &show_bgp_updgrps_adj_cmd); - install_element(VIEW_NODE, &show_bgp_updgrps_adj_s_cmd); - install_element(VIEW_NODE, &show_bgp_updgrps_afi_adj_cmd); - install_element(VIEW_NODE, &show_bgp_updgrps_afi_adj_s_cmd); install_element(VIEW_NODE, &show_bgp_updgrps_stats_cmd); - install_element(VIEW_NODE, &show_ip_bgp_instance_updgrps_adj_cmd); install_element(VIEW_NODE, &show_ip_bgp_instance_updgrps_adj_s_cmd); install_element(VIEW_NODE, &show_ip_bgp_summary_cmd); - install_element(VIEW_NODE, &show_ip_bgp_updgrps_adj_cmd); - install_element(VIEW_NODE, &show_ip_bgp_updgrps_adj_s_cmd); install_element(VIEW_NODE, &show_ip_bgp_updgrps_cmd); /* "show [ip] bgp neighbors" commands. */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index daa7ccbf42..029b3d4d36 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1054,6 +1054,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, else continue; + api_nh = &api.nexthops[valid_nh_count]; + api_nh->vrf_id = bgp->vrf_id; + if (nh_family == AF_INET) { struct in_addr *nexthop; @@ -1078,9 +1081,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nexthop = &mpinfo_cp->attr->nexthop; - api_nh = &api.nexthops[valid_nh_count]; api_nh->gate.ipv4 = *nexthop; - api_nh->vrf_id = bgp->vrf_id; /* EVPN type-2 routes are programmed as onlink on l3-vni SVI */ @@ -1135,7 +1136,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (ifindex == 0) continue; - api_nh = &api.nexthops[valid_nh_count]; api_nh->gate.ipv6 = *nexthop; api_nh->ifindex = ifindex; api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index c06339aad9..e8ea2b717f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -108,7 +108,8 @@ static int bgp_check_main_socket(bool create, struct bgp *bgp) struct listnode *bgpnode, *nbgpnode; struct bgp *bgp_temp; - if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF && + vrf_is_mapped_on_netns(bgp->vrf_id)) return 0; if (create == true) { if (bgp_server_main_created) diff --git a/doc/OSPF-SR.rst b/doc/OSPF-SR.rst index 0ee1a12f28..299a7e1c87 100644 --- a/doc/OSPF-SR.rst +++ b/doc/OSPF-SR.rst @@ -5,6 +5,26 @@ This is an EXPERIMENTAL support of draft `draft-ietf-ospf-segment-routing-extensions-24`. DON'T use it for production network. +Supported Features +------------------ + +* Automatic computation of Primary and Backup Adjacency SID with + Cisco experimental remote IP address +* SRGB configuration +* Prefix configuration for Node SID with optional NO-PHP flag (Linux + kernel support both mode) +* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels + could be stack) +* Automatic provisioning of MPLS table +* Static route configuration with label stack up to 32 labels + +Interoperability +---------------- + +* tested on various topology including point-to-point and LAN interfaces + in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x +* check OSPF LSA conformity with latest wireshark release 2.5.0-rc + Implementation details ---------------------- @@ -248,9 +268,6 @@ Known limitations * MPLS table are not flush at startup. Thus, restarting zebra process is mandatory to remove old MPLS entries in the data plane after a crash of ospfd daemon -* Due to a bug in OSPF Opaque, LSA are not flood when enable Segment Routing - through CLI once OSPFd started. You must configure Segment Routing within - configuration file before launching OSPFd * With NO Penultimate Hop Popping, it is not possible to express a Segment Path with an Adjacency SID due to the impossibility for the Linux Kernel to perform double POP instruction. diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 33341d2be6..9694be1efe 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -759,10 +759,11 @@ currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR node to request to its neighbor to not pop the label. @end deffn -@deffn {Command} {show ip ospf database segment-routing} {} -@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {} -@deffnx {Command} {show ip ospf database segment-routing self-originate} {} +@deffn {Command} {show ip ospf database segment-routing [json]} {} +@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router} [json]} {} +@deffnx {Command} {show ip ospf database segment-routing self-originate [json]} {} Show Segment Routing Data Base, all SR nodes, specific advertized router or self router. +Optional Json output could be obtain by adding 'json' at the end of the command. @end deffn @node Debugging OSPF diff --git a/lib/command.c b/lib/command.c index 10996d5dd4..3fa086bf62 100644 --- a/lib/command.c +++ b/lib/command.c @@ -500,6 +500,9 @@ static int config_write_host(struct vty *vty) if (cmd_hostname_get()) vty_out(vty, "hostname %s\n", cmd_hostname_get()); + if (cmd_domainname_get()) + vty_out(vty, "domainname %s\n", cmd_domainname_get()); + if (host.encrypt) { if (host.password_encrypt) vty_out(vty, "password 8 %s\n", host.password_encrypt); diff --git a/lib/netns_linux.c b/lib/netns_linux.c index 0e955bade9..a92431d1ae 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -43,6 +43,9 @@ DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context") DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name") +/* default NS ID value used when VRF backend is not NETNS */ +#define NS_DEFAULT_INTERNAL 0 + static inline int ns_compare(const struct ns *ns, const struct ns *ns2); static struct ns *ns_lookup_name_internal(const char *name); @@ -414,8 +417,10 @@ void ns_init(void) #ifdef HAVE_NETNS if (have_netns_enabled < 0) ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY); - else + else { ns_default_ns_fd = -1; + default_ns = NULL; + } #else ns_default_ns_fd = -1; default_ns = NULL; @@ -534,6 +539,6 @@ ns_id_t ns_get_default_id(void) { if (default_ns) return default_ns->ns_id; - return NS_UNKNOWN; + return NS_DEFAULT_INTERNAL; } diff --git a/lib/zclient.c b/lib/zclient.c index ad91eb504b..8535c3b5f5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1085,7 +1085,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETC(s, api->message); STREAM_GETC(s, api->safi); if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - stream_get(&(api->rmac), s, sizeof(struct ethaddr)); + STREAM_GET(&(api->rmac), s, sizeof(struct ethaddr)); /* Prefix. */ STREAM_GETC(s, api->prefix.family); @@ -1266,6 +1266,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) break; } + STREAM_GETC(s, nhr->type); + STREAM_GETW(s, nhr->instance); STREAM_GETC(s, nhr->distance); STREAM_GETL(s, nhr->metric); STREAM_GETC(s, nhr->nexthop_num); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 11f9e7c7b6..b52f1cef6c 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -204,26 +204,142 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, { struct ospf6_route *old_route; struct ospf6_path *ecmp_path, *o_path = NULL; - struct listnode *anode; + struct listnode *anode, *anext; struct listnode *nnode, *rnode, *rnext; struct ospf6_nexthop *nh, *rnh; char buf[PREFIX2STR_BUFFER]; bool route_found = false; + /* check for old entry match with new route origin, + * delete old entry. + */ for (old_route = old; old_route; old_route = old_route->next) { - if (ospf6_route_is_same(old_route, route) && - (old_route->path.type == route->path.type) && - (old_route->path.cost == route->path.cost) && - (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + bool route_updated = false; + + if (!ospf6_route_is_same(old_route, route) || + (old_route->path.type != route->path.type)) + continue; + + /* Current and New route has same origin, + * delete old entry. + */ + for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, + o_path)) { + /* Check old route path and route has same + * origin. + */ + if (o_path->area_id != route->path.area_id || + (memcmp(&(o_path)->origin, &(route)->path.origin, + sizeof(struct ospf6_ls_origin)) != 0)) + continue; + + /* Cost is not same then delete current path */ + if ((o_path->cost == route->path.cost) && + (o_path->u.cost_e2 == route->path.u.cost_e2)) + continue; if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&old_route->prefix, buf, sizeof(buf)); - zlog_debug("%s: old route %s path cost %u [%u]", + zlog_debug("%s: route %s cost old %u new %u is not same, replace route", + __PRETTY_FUNCTION__, buf, + o_path->cost, route->path.cost); + } + + /* Remove selected current rout path's nh from + * effective nh list. + */ + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) { + for (ALL_LIST_ELEMENTS(old_route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, nh)) + continue; + listnode_delete(old_route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + route_updated = true; + } + } + + listnode_delete(old_route->paths, o_path); + ospf6_path_free(o_path); + + /* Current route's path (adv_router info) is similar + * to route being added. + * Replace current route's path with paths list head. + * Update FIB with effective NHs. + */ + if (listcount(old_route->paths)) { + if (old_route->path.origin.id == + route->path.origin.id && + old_route->path.origin.adv_router == + route->path.origin.adv_router) { + struct ospf6_path *h_path; + + h_path = (struct ospf6_path *) + listgetdata(listhead(old_route->paths)); + old_route->path.origin.type = + h_path->origin.type; + old_route->path.origin.id = + h_path->origin.id; + old_route->path.origin.adv_router = + h_path->origin.adv_router; + } + + if (route_updated) { + for (ALL_LIST_ELEMENTS(old_route->paths, + anode, anext, o_path)) { + ospf6_merge_nexthops( + old_route->nh_list, + o_path->nh_list); + } + /* Update RIB/FIB with effective + * nh_list + */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + break; + } + } else { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.", + __PRETTY_FUNCTION__, buf, + old_route->path.cost, + route->path.cost); + } + ospf6_route_remove(old_route, + ospf6->route_table); + break; + } + } + if (route_updated) + break; + } + + /* Add new route */ + for (old_route = old; old_route; old_route = old_route->next) { + + /* Current and New Route prefix or route type + * is not same skip this current node. + */ + if (!ospf6_route_is_same(old_route, route) || + (old_route->path.type != route->path.type)) + continue; + + /* Old Route and New Route have Equal Cost, Merge NHs */ + if ((old_route->path.cost == route->path.cost) && + (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: old route %s path cost %u e2 %u", __PRETTY_FUNCTION__, buf, old_route->path.cost, - ospf6_route_is_same(old_route, - route)); + old_route->path.u.cost_e2); } route_found = true; /* check if this path exists already in @@ -232,9 +348,10 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, */ for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, o_path)) { - if ((o_path->origin.id == route->path.origin.id) - && (o_path->origin.adv_router == - route->path.origin.adv_router)) + if (o_path->area_id == route->path.area_id && + (memcmp(&(o_path)->origin, + &(route)->path.origin, + sizeof(struct ospf6_ls_origin)) == 0)) break; } /* If path is not found in old_route paths's list, @@ -262,12 +379,13 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("%s: route %s another path added with nh %u, Paths %u", + zlog_debug("%s: route %s another path added with nh %u, effective paths %u nh %u", __PRETTY_FUNCTION__, buf, listcount(ecmp_path->nh_list), old_route->paths ? listcount(old_route->paths) - : 0); + : 0, + listcount(old_route->nh_list)); } } else { for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, @@ -313,6 +431,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, * route. */ ospf6_route_delete(route); + break; } } @@ -426,11 +545,12 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) } -void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) +void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, + struct ospf6_route *asbr_entry) { struct ospf6_as_external_lsa *external; struct prefix prefix; - struct ospf6_route *route, *nroute; + struct ospf6_route *route, *nroute, *route_to_del; char buf[PREFIX2STR_BUFFER]; external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( @@ -445,6 +565,35 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) return; } + route_to_del = ospf6_route_create(); + route_to_del->type = OSPF6_DEST_TYPE_NETWORK; + route_to_del->prefix.family = AF_INET6; + route_to_del->prefix.prefixlen = external->prefix.prefix_length; + ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, + &external->prefix); + + route_to_del->path.origin.type = lsa->header->type; + route_to_del->path.origin.id = lsa->header->id; + route_to_del->path.origin.adv_router = lsa->header->adv_router; + + if (asbr_entry) { + route_to_del->path.area_id = asbr_entry->path.area_id; + if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) { + route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2; + route_to_del->path.metric_type = 2; + route_to_del->path.cost = asbr_entry->path.cost; + route_to_del->path.u.cost_e2 = + OSPF6_ASBR_METRIC(external); + } else { + route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1; + route_to_del->path.metric_type = 1; + route_to_del->path.cost = + asbr_entry->path.cost + + OSPF6_ASBR_METRIC(external); + route_to_del->path.u.cost_e2 = 0; + } + } + memset(&prefix, 0, sizeof(struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; @@ -459,14 +608,25 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) return; } - for (ospf6_route_lock(route); - route && ospf6_route_is_prefix(&prefix, route); route = nroute) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u", + __PRETTY_FUNCTION__, buf, route->path.cost, + route->path.u.cost_e2, + route_to_del->path.cost, + route_to_del->path.u.cost_e2); + } + + for (ospf6_route_lock(route); route && + ospf6_route_is_prefix(&prefix, route); route = nroute) { nroute = ospf6_route_next(route); + if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; - /* Route has multiple ECMP paths remove, - * matching path and update effective route's nh list. + /* Route has multiple ECMP paths, remove matching + * path. Update current route's effective nh list + * after removal of one of the path. */ if (listcount(route->paths) > 1) { struct listnode *anode, *anext; @@ -481,18 +641,36 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) */ for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path)) { - if (o_path->origin.type != lsa->header->type) - continue; - if (o_path->origin.id != lsa->header->id) + if ((o_path->origin.type != lsa->header->type) + || (o_path->origin.adv_router != + lsa->header->adv_router) || + (o_path->origin.id != lsa->header->id)) continue; - if (o_path->origin.adv_router != - lsa->header->adv_router) + + /* Compare LSA cost with current + * route info. + */ + if (!asbr_entry && (o_path->cost != + route_to_del->path.cost || + o_path->u.cost_e2 != + route_to_del->path.u.cost_e2)) { + if (IS_OSPF6_DEBUG_EXAMIN( + AS_EXTERNAL)) { + prefix2str(&prefix, buf, + sizeof(buf)); + zlog_debug( + "%s: route %s to delete is not same, cost %u del cost %u. skip", + __PRETTY_FUNCTION__, buf, + route->path.cost, + route_to_del->path.cost); + } continue; + } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&prefix, buf, sizeof(buf)); zlog_debug( - "%s: route %s path found with nh %u", + "%s: route %s path found with nh %u to remove.", __PRETTY_FUNCTION__, buf, listcount(o_path->nh_list)); } @@ -542,13 +720,13 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) listcount(route->nh_list)); } - /* Update RIB/FIB w/ effective nh_list */ + /* Update RIB/FIB with effective nh_list */ if (ospf6->route_table->hook_add) (*ospf6->route_table->hook_add)(route); - /* route's path is similar to lsa header, - * replace route's path with route's - * paths list head. + /* route's primary path is similar to LSA, + * replace route's primary path with + * route's paths list head. */ if (route->path.origin.id == lsa->header->id && route->path.origin.adv_router == @@ -568,12 +746,29 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) continue; } else { - if (route->path.origin.type != lsa->header->type) - continue; - if (route->path.origin.id != lsa->header->id) + /* Compare LSA origin and cost with current route info. + * if any check fails skip del this route node. + */ + if (asbr_entry && (!ospf6_route_is_same_origin(route, + route_to_del) || + (route->path.type != route_to_del->path.type) || + (route->path.cost != route_to_del->path.cost) || + (route->path.u.cost_e2 != + route_to_del->path.u.cost_e2))) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: route %s to delete is not same, cost %u del cost %u. skip", + __PRETTY_FUNCTION__, buf, + route->path.cost, + route_to_del->path.cost); + } continue; - if (route->path.origin.adv_router != - lsa->header->adv_router) + } + + if ((route->path.origin.type != lsa->header->type) || + (route->path.origin.adv_router != + lsa->header->adv_router) || + (route->path.origin.id != lsa->header->id)) continue; } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { @@ -589,6 +784,8 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) } if (route != NULL) ospf6_route_unlock(route); + + ospf6_route_delete(route_to_del); } void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry) @@ -622,7 +819,7 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry) type = htons(OSPF6_LSTYPE_AS_EXTERNAL); router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix); for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) - ospf6_asbr_lsa_remove(lsa); + ospf6_asbr_lsa_remove(lsa, asbr_entry); } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index cc4f0272aa..bd160a6456 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -71,7 +71,8 @@ struct ospf6_as_external_lsa { } extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa); -extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa); +extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, + struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 19eb9a3fe6..ef0a093d13 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -469,6 +469,8 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb) if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (ra->path.u.cost_e2 != rb->path.u.cost_e2) return (ra->path.u.cost_e2 - rb->path.u.cost_e2); + else + return (ra->path.cost - rb->path.cost); } else { if (ra->path.cost != rb->path.cost) return (ra->path.cost - rb->path.cost); @@ -627,10 +629,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (ospf6_route_is_identical(old, route)) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: needless update of %p", + "%s %p: route add %p: needless update of %p old cost %u", ospf6_route_table_name(table), (void *)table, (void *)route, - (void *)old); + (void *)old, old->path.cost); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: needless update", ospf6_route_table_name(table)); @@ -645,9 +647,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, } if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route add %p: update of %p", + zlog_debug("%s %p: route add %p cost %u: update of %p old cost %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)old); + (void *)route, route->path.cost, (void *)old, + old->path.cost); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: update", ospf6_route_table_name(table)); @@ -686,13 +689,14 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (prev || next) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: another path: prev %p, next %p node refcount %u", + "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)prev, (void *)next, - node->lock); + (void *)route, route->path.cost, (void *)prev, + (void *)next, node->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) - zlog_debug("%s: route add: another path found", - ospf6_route_table_name(table)); + zlog_debug("%s: route add cost %u: another path found", + ospf6_route_table_name(table), + route->path.cost); if (prev == NULL) prev = next->prev; @@ -814,9 +818,9 @@ void ospf6_route_remove(struct ospf6_route *route, prefix2str(&route->prefix, buf, sizeof(buf)); if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route remove %p: %s refcount %u", + zlog_debug("%s %p: route remove %p: %s cost %u refcount %u", ospf6_route_table_name(table), (void *)table, - (void *)route, buf, route->lock); + (void *)route, buf, route->path.cost, route->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route remove: %s", ospf6_route_table_name(table), buf); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 25d968fb68..afe2d7397b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -72,7 +72,7 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa) { switch (ntohs(lsa->header->type)) { case OSPF6_LSTYPE_AS_EXTERNAL: - ospf6_asbr_lsa_remove(lsa); + ospf6_asbr_lsa_remove(lsa, NULL); break; default: @@ -96,11 +96,16 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route) static void ospf6_top_brouter_hook_add(struct ospf6_route *route) { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - char buf[PREFIX2STR_BUFFER]; - - prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("%s: brouter %s add with nh count %u", - __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + uint32_t brouter_id; + char brouter_name[16]; + + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); + zlog_debug("%s: brouter %s add with adv router %x nh count %u", + __PRETTY_FUNCTION__, brouter_name, + route->path.origin.adv_router, + listcount(route->nh_list)); } ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_add(route); @@ -110,11 +115,15 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route) static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - char buf[PREFIX2STR_BUFFER]; + uint32_t brouter_id; + char brouter_name[16]; - prefix2str(&route->prefix, buf, sizeof(buf)); + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); zlog_debug("%s: brouter %s del with nh count %u", - __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + __PRETTY_FUNCTION__, brouter_name, + listcount(route->nh_list)); } route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 7bd644f43d..8dbf39ef5d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -55,7 +55,7 @@ /* ospfd privileges */ zebra_capabilities_t _caps_p[] = { - ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, + ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN }; struct zebra_privs_t ospfd_privs = { diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..fef77f574e 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -47,6 +47,7 @@ #include "thread.h" #include "vty.h" #include "zclient.h" +#include <lib/json.h> #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -306,7 +307,8 @@ int ospf_sr_init(void) { int rc = -1; - zlog_info("SR (%s): Initialize SR Data Base", __func__); + if (IS_DEBUG_OSPF_SR) + zlog_info("SR (%s): Initialize SR Data Base", __func__); memset(&OspfSR, 0, sizeof(struct ospf_sr_db)); OspfSR.enabled = false; @@ -675,6 +677,7 @@ static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe) SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); api_nh->labels[0] = nhlfe.label_out; api_nh->label_num = 1; + api_nh->vrf_id = VRF_DEFAULT; api.nexthop_num = 1; } @@ -1616,11 +1619,11 @@ static int ospf_sr_update_schedule(struct thread *t) monotime(&stop_time); - zlog_info( - "SR (%s): SPF Processing Time(usecs): %lld\n", - __func__, - (stop_time.tv_sec - start_time.tv_sec) * 1000000LL - + (stop_time.tv_usec - start_time.tv_usec)); + if (IS_DEBUG_OSPF_SR) + zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n", + __func__, + (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + + (stop_time.tv_usec - start_time.tv_usec)); OspfSR.update = false; return 1; @@ -2128,91 +2131,197 @@ DEFUN (no_sr_prefix_sid, -static void show_vty_sr_node(struct vty *vty, struct sr_node *srn) +static void show_sr_node(struct vty *vty, struct json_object *json, + struct sr_node *srn) { struct listnode *node; struct sr_link *srl; struct sr_prefix *srp; struct interface *itf; - char pref[16]; + char pref[19]; char sid[22]; char label[8]; + json_object *json_node = NULL, *json_algo, *json_obj; + json_object *json_prefix = NULL, *json_link = NULL; /* Sanity Check */ if (srn == NULL) return; - vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); - vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size, - srn->srgb.lower_bound); - vty_out(vty, "\tAlgorithm(s): %s", - srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); - for (int i = 1; i < ALGORITHM_COUNT; i++) { - if (srn->algo[i] == SR_ALGORITHM_UNSET) - continue; - vty_out(vty, "/%s", - srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); - } - if (srn->msd != 0) - vty_out(vty, "\tMSD: %u", srn->msd); - - vty_out(vty, - "\n\n Prefix or Link Label In Label Out " - "Node or Adj. SID Interface Nexthop\n"); - vty_out(vty, - "------------------ -------- --------- " - "--------------------- --------- ---------------\n"); + if (json) { + json_node = json_object_new_object(); + json_object_string_add(json_node, "routerID", + inet_ntoa(srn->adv_router)); + json_object_int_add(json_node, "srgbSize", + srn->srgb.range_size); + json_object_int_add(json_node, "srgbLabel", + srn->srgb.lower_bound); + json_algo = json_object_new_array(); + json_object_object_add(json_node, "algorithms", json_algo); + for (int i = 0; i < ALGORITHM_COUNT; i++) { + if (srn->algo[i] == SR_ALGORITHM_UNSET) + continue; + json_obj = json_object_new_object(); + char tmp[2]; + + snprintf(tmp, 2, "%u", i); + json_object_string_add(json_obj, tmp, + srn->algo[i] == SR_ALGORITHM_SPF ? + "SPF" : "S-SPF"); + json_object_array_add(json_algo, json_obj); + } + if (srn->msd != 0) + json_object_int_add(json_node, "nodeMsd", srn->msd); + } else { + vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); + vty_out(vty, "\tSRGB (Size/Label): %u/%u", + srn->srgb.range_size, srn->srgb.lower_bound); + vty_out(vty, "\tAlgorithm(s): %s", + srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); + for (int i = 1; i < ALGORITHM_COUNT; i++) { + if (srn->algo[i] == SR_ALGORITHM_UNSET) + continue; + vty_out(vty, "/%s", + srn->algo[i] == SR_ALGORITHM_SPF ? + "SPF" : "S-SPF"); + } + if (srn->msd != 0) + vty_out(vty, "\tMSD: %u", srn->msd); + } + + if (!json) { + vty_out(vty, + "\n\n Prefix or Link Label In Label Out " + "Node or Adj. SID Interface Nexthop\n"); + vty_out(vty, + "------------------ -------- --------- " + "--------------------- --------- ---------------\n"); + } for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { - strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16); + snprintf(pref, 19, "%s/%u", + inet_ntoa(srp->nhlfe.prefv4.prefix), + srp->nhlfe.prefv4.prefixlen); snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid); if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL) sprintf(label, "pop"); else sprintf(label, "%u", srp->nhlfe.label_out); itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label, - sid, itf ? itf->name : "-", - inet_ntoa(srp->nhlfe.nexthop)); + if (json) { + if (!json_prefix) { + json_prefix = json_object_new_array(); + json_object_object_add(json_node, + "extendedPrefix", json_prefix); + } + json_obj = json_object_new_object(); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srp->sid); + json_object_int_add(json_obj, "inputLabel", + srp->nhlfe.label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srp->nhlfe.nexthop)); + json_object_array_add(json_prefix, json_obj); + } else { + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srp->nhlfe.label_in, label, + sid, itf ? itf->name : "-", + inet_ntoa(srp->nhlfe.nexthop)); + } } for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) { - strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16); + snprintf(pref, 19, "%s/%u", + inet_ntoa(srl->nhlfe[0].prefv4.prefix), + srl->nhlfe[0].prefv4.prefixlen); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]); if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL) sprintf(label, "pop"); else sprintf(label, "%u", srl->nhlfe[0].label_out); itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in, - label, sid, itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[0].nexthop)); - snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); - if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) - sprintf(label, "pop"); - else - sprintf(label, "%u", srl->nhlfe[0].label_out); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in, - label, sid, itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[1].nexthop)); + if (json) { + if (!json_link) { + json_link = json_object_new_array(); + json_object_object_add(json_node, + "extendedLink", json_link); + } + /* Primary Link */ + json_obj = json_object_new_object(); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srl->sid[0]); + json_object_int_add(json_obj, "inputLabel", + srl->nhlfe[0].label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srl->nhlfe[0].nexthop)); + json_object_array_add(json_link, json_obj); + /* Backup Link */ + json_obj = json_object_new_object(); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) + sprintf(label, "pop"); + else + sprintf(label, "%u", srl->nhlfe[0].label_out); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srl->sid[1]); + json_object_int_add(json_obj, "inputLabel", + srl->nhlfe[1].label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srl->nhlfe[1].nexthop)); + json_object_array_add(json_link, json_obj); + } else { + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srl->nhlfe[0].label_in, + label, sid, itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[0].nexthop)); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) + sprintf(label, "pop"); + else + sprintf(label, "%u", srl->nhlfe[1].label_out); + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srl->nhlfe[1].label_in, + label, sid, itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[1].nexthop)); + } } - vty_out(vty, "\n"); + if (json) + json_object_array_add(json, json_node); + else + vty_out(vty, "\n"); } -static void show_srdb_entry(struct hash_backet *backet, void *args) +static void show_vty_srdb(struct hash_backet *backet, void *args) { struct vty *vty = (struct vty *)args; struct sr_node *srn = (struct sr_node *)backet->data; - show_vty_sr_node(vty, srn); + show_sr_node(vty, NULL, srn); +} + +static void show_json_srdb(struct hash_backet *backet, void *args) +{ + struct json_object *json = (struct json_object *)args; + struct sr_node *srn = (struct sr_node *)backet->data; + + show_sr_node(NULL, json, srn); } DEFUN (show_ip_opsf_srdb, show_ip_ospf_srdb_cmd, - "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]", + "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]", SHOW_STR IP_STR OSPF_STR @@ -2220,23 +2329,41 @@ DEFUN (show_ip_opsf_srdb, "Show Segment Routing Data Base\n" "Advertising SR node\n" "Advertising SR node ID (as an IP address)\n" - "Self-originated SR node\n") + "Self-originated SR node\n" + JSON_STR) { int idx = 0; struct in_addr rid; struct sr_node *srn; + u_char uj = use_json(argc, argv); + json_object *json = NULL, *json_node_array = NULL; if (!OspfSR.enabled) { vty_out(vty, "Segment Routing is disabled on this router\n"); return CMD_WARNING; } - vty_out(vty, "\n OSPF Segment Routing database for ID %s\n\n", - inet_ntoa(OspfSR.self->adv_router)); + if (uj) { + json = json_object_new_object(); + json_node_array = json_object_new_array(); + json_object_string_add(json, "srdbID", + inet_ntoa(OspfSR.self->adv_router)); + json_object_object_add(json, "srNodes", json_node_array); + } else { + vty_out(vty, + "\n\t\tOSPF Segment Routing database for ID %s\n\n", + inet_ntoa(OspfSR.self->adv_router)); + } if (argv_find(argv, argc, "self-originate", &idx)) { srn = OspfSR.self; - show_vty_sr_node(vty, srn); + show_sr_node(vty, json_node_array, srn); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -2250,15 +2377,32 @@ DEFUN (show_ip_opsf_srdb, /* Get the SR Node from the SRDB */ srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, (void *)&rid); - show_vty_sr_node(vty, srn); + show_sr_node(vty, json_node_array, srn); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } /* No parameters have been provided, Iterate through all the SRDB */ - hash_iterate( - OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))show_srdb_entry, - (void *)vty); + if (uj) { + hash_iterate( + OspfSR.neighbors, + (void (*)(struct hash_backet *, void *))show_json_srdb, + (void *)json_node_array); + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + hash_iterate( + OspfSR.neighbors, + (void (*)(struct hash_backet *, void *))show_vty_srdb, + (void *)vty); + } return CMD_SUCCESS; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 79af4a55fb..b3c4e4a365 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -707,6 +707,7 @@ static void ospf_finish_final(struct ospf *ospf) OSPF_TIMER_OFF(ospf->t_read); OSPF_TIMER_OFF(ospf->t_write); OSPF_TIMER_OFF(ospf->t_opaque_lsa_self); + OSPF_TIMER_OFF(ospf->t_sr_update); close(ospf->fd); stream_free(ospf->ibuf); diff --git a/tests/.gitignore b/tests/.gitignore index ab1d55b548..c2fe9c8890 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -24,10 +24,12 @@ __pycache__ /bgpd/test_ecommunity /bgpd/test_mp_attr /bgpd/test_mpath +/bgpd/test_packet /isisd/test_fuzz_isis_tlv /isisd/test_fuzz_isis_tlv_tests.h /isisd/test_isis_vertex_queue /lib/cli/test_cli +/lib/cli/test_cli_clippy.c /lib/cli/test_commands /lib/cli/test_commands_defun.c /lib/test_buffer @@ -38,6 +40,7 @@ __pycache__ /lib/test_memory /lib/test_nexthop_iter /lib/test_privs +/lib/test_ringbuf /lib/test_srcdest_table /lib/test_segv /lib/test_sig @@ -48,3 +51,4 @@ __pycache__ /lib/test_ttable /lib/test_zmq /ospf6d/test_lsdb +/ospf6d/test_lsdb_clippy.c diff --git a/tests/lib/test_ringbuf.py b/tests/lib/test_ringbuf.py index 860d872f86..5d994ddd7b 100644 --- a/tests/lib/test_ringbuf.py +++ b/tests/lib/test_ringbuf.py @@ -1,4 +1,6 @@ import frrtest -class TestRingbuf(frrtest.TestExitNonzero): +class TestRingbuf(frrtest.TestMultiOut): program = './test_ringbuf' + +TestRingbuf.exit_cleanly() diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 8719226281..bf9d70bae9 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -539,7 +539,7 @@ int vtysh_mark_file(const char *filename) } vty = vty_new(); - vty->fd = 0; /* stdout */ + vty->wfd = STDERR_FILENO; vty->type = VTY_TERM; vty->node = CONFIG_NODE; diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index aa1dd407eb..c055d29d4b 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -398,7 +398,7 @@ static int vtysh_read_file(FILE *confp) int ret; vty = vty_new(); - vty->fd = 0; /* stdout */ + vty->wfd = STDERR_FILENO; vty->type = VTY_TERM; vty->node = CONFIG_NODE; @@ -448,6 +448,11 @@ void vtysh_config_write() sprintf(line, "hostname %s", cmd_hostname_get()); vtysh_config_parse_line(NULL, line); } + + if (cmd_domainname_get()) { + sprintf(line, "domainname %s", cmd_domainname_get()); + vtysh_config_parse_line(NULL, line); + } if (vtysh_write_integrated == WRITE_INTEGRATED_NO) vtysh_config_parse_line(NULL, "no service integrated-vtysh-config"); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 9fc5afff0f..d960dbd937 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1019,6 +1019,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, break; } if (re) { + stream_putc(s, re->type); + stream_putw(s, re->instance); stream_putc(s, re->distance); stream_putl(s, re->metric); num = 0; @@ -1054,6 +1056,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, } stream_putc_at(s, nump, num); } else { + stream_putc(s, 0); // type + stream_putw(s, 0); // instance stream_putc(s, 0); // distance stream_putl(s, 0); // metric stream_putc(s, 0); // nexthops diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 20b9e94288..e07dc6059f 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1135,7 +1135,8 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n", zvni->vni, "L2", zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", - num_macs, num_neigh, num_vteps, + num_macs, num_neigh, + num_vteps, vrf_id_to_name(zvni->vrf_id)); else { char vni_str[VNI_STR_LEN]; @@ -1858,20 +1859,18 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, return -1; /* only need to delete the entry from bgp if we sent it before */ - if (advertise_gw_macip_enabled(zvni)) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", - ifp->vrf_id, ifp->name, - ifp->ifindex, zvni->vni, - prefix_mac2str(&(n->emac), - NULL, - ETHER_ADDR_STRLEN), - ipaddr2str(ip, buf2, sizeof(buf2))); - - /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, - ZEBRA_MACIP_TYPE_GW); - } + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", + ifp->vrf_id, ifp->name, + ifp->ifindex, zvni->vni, + prefix_mac2str(&(n->emac), + NULL, + ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2))); + + /* Remove neighbor from BGP. */ + zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, + ZEBRA_MACIP_TYPE_GW); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -6256,15 +6255,33 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->local_vtep_ip = vxl->vtep_ip; if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up( zl3vni); } } + /* + * local-ip change - process oper down, associate with new + * local-ip and then process oper up again + */ + if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (if_is_operative(ifp)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zl3vni->local_vtep_ip = vxl->vtep_ip; + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up( + zl3vni); + } + } + + /* Update local tunnel IP. */ + zl3vni->local_vtep_ip = vxl->vtep_ip; + /* if we have a valid new master, process l3-vni oper up */ if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { - if (is_l3vni_oper_up(zl3vni)) + if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } } else { @@ -6704,6 +6721,10 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, struct interface *vlan_if = NULL; struct interface *vrr_if = NULL; + zvni = zvni_lookup(vni); + if (!zvni) + return 0; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "EVPN gateway macip Adv %s on VNI %d , currently %s", @@ -6712,10 +6733,6 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, ? "enabled" : "disabled"); - zvni = zvni_lookup(vni); - if (!zvni) - return 0; - if (zvni->advertise_gw_macip == advertise) return 0; diff --git a/zebra/zserv.c b/zebra/zserv.c index 98cb54f7b8..bca8a509d8 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1166,12 +1166,12 @@ static int zread_route_add(struct zserv *client, u_short length, switch (api_nh->type) { case NEXTHOP_TYPE_IFINDEX: nexthop = route_entry_nexthop_ifindex_add( - re, api_nh->ifindex, re->vrf_id); + re, api_nh->ifindex, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4: nexthop = route_entry_nexthop_ipv4_add( re, &api_nh->gate.ipv4, NULL, - re->vrf_id); + api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4_IFINDEX: { @@ -1188,7 +1188,7 @@ static int zread_route_add(struct zserv *client, u_short length, nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &api_nh->gate.ipv4, NULL, ifindex, - re->vrf_id); + api_nh->vrf_id); /* if this an EVPN route entry, program the nh as neigh @@ -1211,12 +1211,12 @@ static int zread_route_add(struct zserv *client, u_short length, } case NEXTHOP_TYPE_IPV6: nexthop = route_entry_nexthop_ipv6_add( - re, &api_nh->gate.ipv6, re->vrf_id); + re, &api_nh->gate.ipv6, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV6_IFINDEX: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &api_nh->gate.ipv6, api_nh->ifindex, - re->vrf_id); + api_nh->vrf_id); break; case NEXTHOP_TYPE_BLACKHOLE: nexthop = route_entry_nexthop_blackhole_add( |
