forked from Mirror/frr
Merge branch 'master' of https://github.com/frrouting/frr into evpn-ipv6-tenant-routing
Conflicts: zebra/zserv.c
This commit is contained in:
commit
bfd498f0da
30
COMMUNITY.md
30
COMMUNITY.md
|
@ -492,6 +492,36 @@ In all cases, compatibility pieces should be marked with compiler/preprocessor
|
|||
annotations to print warnings at compile time, pointing to the appropriate
|
||||
update path. A `-Werror` build should fail if compatibility bits are used.
|
||||
|
||||
### Release Process/Schedule
|
||||
|
||||
FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
|
||||
|
||||
* MAJOR - Significant new features or multiple minor features
|
||||
A example of a MAJOR feature is a New Routing Protocol
|
||||
* MINOR - Smaller Features
|
||||
A example of a MINOR feature is the addition of the BGP Shutdown feature.
|
||||
* BUGFIX - Fixes for actual bugs and/or security issues.
|
||||
|
||||
We will pull a new development branch for the next release every 4 months.
|
||||
The current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR
|
||||
release is made at the time of branch pull based on what has been received
|
||||
the previous 4 months. The branch name will be dev/MAJOR.MINOR. At
|
||||
this point in time the master branch configure.ac and packaging systems
|
||||
will be updated to reflect the next possible release name to allow
|
||||
for easy distinguishing. Additionally the new dev branch will have
|
||||
these files updated too.
|
||||
|
||||
After one month the development branch will be renamed to
|
||||
stable/MAJOR.MINOR. This process is not held up unless a crash or
|
||||
security issue has been found and needs to be addressed. Issues
|
||||
being fixed will not cause a delay.
|
||||
|
||||
Bug fix releases are at 1 month intervals until next MAJOR.MINOR is
|
||||
pulled. Then at that time as needed for issues filed.
|
||||
|
||||
Security issues are fixed for 1 year minimum on old releases and
|
||||
normal bug fixes for the current and previous release
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
|
||||
|
|
|
@ -1754,8 +1754,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)
|
||||
|
@ -1783,7 +1785,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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3253,15 +3255,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3282,10 +3294,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)
|
||||
|
@ -3313,11 +3321,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) {
|
||||
|
@ -3330,7 +3339,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);
|
||||
|
@ -4457,8 +4465,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,
|
||||
|
@ -4476,24 +4484,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 (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))
|
||||
&& 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;
|
||||
|
||||
/* Local tunnel endpoint IP address has changed */
|
||||
handle_tunnel_ip_change(bgp, vpn, originator_ip);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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. */
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1026,14 +1026,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
|||
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|
||||
|| info->sub_type == BGP_ROUTE_AGGREGATE) {
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
}
|
||||
|
||||
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
||||
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|
||||
|| bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
|
||||
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
|
||||
/* Metric is currently based on the best-path only */
|
||||
metric = info->attr->med;
|
||||
|
@ -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;
|
||||
|
@ -1265,14 +1265,14 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
|
|||
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
|
||||
|
||||
if (peer->sort == BGP_PEER_IBGP) {
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
|
||||
}
|
||||
|
||||
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|
||||
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|
||||
|| bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
|
||||
if (bgp_debug_zebra(p)) {
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -86,6 +86,12 @@ static inline char *ipaddr2str(struct ipaddr *ip, char *buf, int size)
|
|||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert IPv4 address to IPv4-mapped IPv6 address which is of the
|
||||
* form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
|
||||
* be used to represent the IPv4 address, wherever only an IPv6 address
|
||||
* is required.
|
||||
*/
|
||||
static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
|
||||
struct in_addr in)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -402,7 +402,7 @@ extern const char *zserv_command_string(unsigned int command);
|
|||
#define strmatch(a,b) (!strcmp((a), (b)))
|
||||
|
||||
/* Zebra message flags */
|
||||
#define ZEBRA_FLAG_INTERNAL 0x01
|
||||
#define ZEBRA_FLAG_ALLOW_RECURSION 0x01
|
||||
#define ZEBRA_FLAG_SELFROUTE 0x02
|
||||
#define ZEBRA_FLAG_IBGP 0x08
|
||||
#define ZEBRA_FLAG_SELECTED 0x10
|
||||
|
|
|
@ -114,7 +114,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix
|
|||
SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
|
||||
break;
|
||||
}
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
api.nexthop_num = 1;
|
||||
|
|
|
@ -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)
|
||||
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.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)
|
||||
/* 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.id != lsa->header->id)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
uint32_t brouter_id;
|
||||
char brouter_name[16];
|
||||
|
||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||
zlog_debug("%s: brouter %s add with nh count %u",
|
||||
__PRETTY_FUNCTION__, buf, listcount(route->nh_list));
|
||||
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));
|
||||
|
|
|
@ -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 = {
|
||||
|
|
262
ospfd/ospf_sr.c
262
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);
|
||||
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];
|
||||
|
||||
vty_out(vty,
|
||||
"\n\n Prefix or Link Label In Label Out "
|
||||
"Node or Adj. SID Interface Nexthop\n");
|
||||
vty_out(vty,
|
||||
"------------------ -------- --------- "
|
||||
"--------------------- --------- ---------------\n");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
372
pimd/TODO
372
pimd/TODO
|
@ -1,375 +1,21 @@
|
|||
T1 DONE Implement debug command
|
||||
test pim receive join
|
||||
|
||||
T2 DONE Implement debug command
|
||||
test pim receive prune
|
||||
|
||||
T3 DONE Per-interface Downstream (S,G) state machine
|
||||
(RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages)
|
||||
|
||||
T4 DONE Upstream (S,G) state machine
|
||||
(RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages)
|
||||
|
||||
T5 DONE Verify Data Packet Forwarding Rules
|
||||
RFC 4601 4.2. Data Packet Forwarding Rules
|
||||
RFC 4601 4.8.2. PIM-SSM-Only Routers
|
||||
|
||||
Additionally, the Packet forwarding rules of Section 4.2 can be
|
||||
simplified in a PIM-SSM-only router:
|
||||
|
||||
iif is the incoming interface of the packet.
|
||||
oiflist = NULL
|
||||
if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
|
||||
oiflist = inherited_olist(S,G)
|
||||
} else if (iif is in inherited_olist(S,G)) {
|
||||
send Assert(S,G) on iif
|
||||
}
|
||||
oiflist = oiflist (-) iif
|
||||
forward packet on all interfaces in oiflist
|
||||
|
||||
Macro:
|
||||
inherited_olist(S,G) =
|
||||
joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
|
||||
|
||||
T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1).
|
||||
Changes in pim_ifchannel.ifassert_winner should trigger
|
||||
pim_upstream_update_join_desired().
|
||||
Depends on TODO T27.
|
||||
Depends on TODO T33.
|
||||
See also CAVEAT C7.
|
||||
See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
|
||||
Transitions from Joined State
|
||||
RPF'(S,G) changes due to an Assert
|
||||
|
||||
http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html:
|
||||
|
||||
The PIM Assert mechanism is used to shutoff duplicate flows onto
|
||||
the same multiaccess network. Routers detect this condiction when
|
||||
they receive an (S,G) packet via a multi-access interface that is
|
||||
in the (S,G) OIL. This causes the routers to send Assert
|
||||
Messages.
|
||||
|
||||
Note that neighbors will not accept Join/Prune or Assert messages
|
||||
from a router unless they have first heard a Hello message from that
|
||||
router. Thus, if a router needs to send a Join/Prune or Assert
|
||||
message on an interface on which it has not yet sent a Hello message
|
||||
with the currently configured IP address, then it MUST immediately
|
||||
send the relevant Hello message without waiting for the Hello Timer
|
||||
to expire, followed by the Join/Prune or Assert message.
|
||||
|
||||
T7 DONE Implement hello option: LAN Prune Delay
|
||||
|
||||
T8 DONE Implement J/P_Override_Interval(I)
|
||||
Depends on TODO T7.
|
||||
See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval.
|
||||
|
||||
T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update.
|
||||
channel_oil vif index accordingly ?
|
||||
Beware accidentaly adding looped MFC entries (IIF=OIF).
|
||||
|
||||
T10 DONE React to (S,G) join directed to another upstream address. See
|
||||
also:
|
||||
|
||||
RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
|
||||
|
||||
If a router wishes to propagate a Join(S,G) upstream, it must also
|
||||
watch for messages on its upstream interface from other routers on
|
||||
that subnet, and these may modify its behavior. If it sees a
|
||||
Join(S,G) to the correct upstream neighbor, it should suppress its
|
||||
own Join(S,G). If it sees a Prune(S,G), Prune(S,G,rpt), or
|
||||
Prune(*,G) to the correct upstream neighbor towards S, it should
|
||||
be prepared to override that prune by scheduling a Join(S,G) to be
|
||||
sent almost immediately.
|
||||
|
||||
T11 DONE Review protocol modifications for SSM
|
||||
(RFC 4601 4.8.1. Protocol Modifications for SSM Destination
|
||||
Addresses)
|
||||
|
||||
T12 DONE Review updates of RPF entries.
|
||||
FIXME pim_upstream.c send_join():
|
||||
Currently only one upstream state is affected by detection of RPF change.
|
||||
RPF change should affect all upstream states sharing the RPF cache.
|
||||
|
||||
T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually
|
||||
implemented with this strategy:
|
||||
rpf_ifch=find_ifch(up->rpf->interface).
|
||||
See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example.
|
||||
|
||||
$ grep -i macro pimd/*.c
|
||||
pimd/pim_iface.c: RFC 4601: 4.1.6. State Summarization Macros
|
||||
pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros
|
||||
pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros
|
||||
pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros
|
||||
pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros
|
||||
pimd/pim_ifchannel.c: Macro:
|
||||
pimd/pim_rpf.c: RFC 4601: 4.1.6. State Summarization Macros
|
||||
|
||||
T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
|
||||
See pim_mroute.c mroute_msg().
|
||||
|
||||
T15 DONE Interface command to statically join (S,G).
|
||||
interface eth0
|
||||
ip igmp join-group 239.1.1.1 source 1.1.1.1
|
||||
|
||||
T16 DONE RPF'(S,G) lookup is not working for S reachable with default route.
|
||||
See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c.
|
||||
Zebra daemon RIB is not reflecting changes in kernel routes
|
||||
accurately?
|
||||
|
||||
T17 DONE Prevent CLI from creating bogus interfaces.
|
||||
Example:
|
||||
conf t
|
||||
interface xxx
|
||||
|
||||
T18 Consider reliable pim solution (refresh reduction)
|
||||
T1 Consider reliable pim solution (refresh reduction)
|
||||
A Reliable Transport Mechanism for PIM
|
||||
http://tools.ietf.org/wg/pim/draft-ietf-pim-port/
|
||||
PORT=PIM-Over-Reliable-Transport
|
||||
|
||||
T19 DONE Fix self as neighbor
|
||||
See mailing list post:
|
||||
http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html
|
||||
|
||||
T20 DONE Fix debug message: "pim_neighbor_update: internal error:
|
||||
trying to replace same prefix list"
|
||||
See mailing list post:
|
||||
http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html
|
||||
|
||||
T21 DONE Clean-up PIM/IGMP interface mismatch debugging
|
||||
See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am
|
||||
See mailing list post:
|
||||
http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html
|
||||
|
||||
T22 DONE IGMP must be protected against adding looped MFC entries
|
||||
created by both source and receiver attached to the same
|
||||
interface.
|
||||
|
||||
T23 DONE libfrr crash after zclient_lookup_nexthop.
|
||||
See mailing list post:
|
||||
http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html
|
||||
|
||||
T24 DONE zserv may return recursive routes:
|
||||
- nexthop type is set to ZEBRA_NEXTHOP_IPV4
|
||||
- ifindex is not reported
|
||||
- calls expecting ifindex (fib_lookup_if_vif_index) are disrupted
|
||||
See also this mailing list post:
|
||||
[PATCH 21/21] Link detect and recursive routes
|
||||
http://www.gossamer-threads.com/lists/quagga/dev/17564
|
||||
|
||||
T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32
|
||||
See also:
|
||||
pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32
|
||||
zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32
|
||||
|
||||
T26 DONE Zebra daemon is marking recursive static route as inactive.
|
||||
|
||||
FIXED: zebra daemon was incorrectly marking recursive routes
|
||||
pointing to kernel routes as inactive:
|
||||
zebra/zebra_rib.c nexthop_active_ipv4:
|
||||
-- Original:
|
||||
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
|
||||
-- Fixed:
|
||||
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) ||
|
||||
match->type == ZEBRA_ROUTE_KERNEL)
|
||||
|
||||
Old problem description:
|
||||
|
||||
This prevents rib_match_ipv4 from returning its nexthop:
|
||||
client: pim_zlookup.c zclient_read_nexthop
|
||||
server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4
|
||||
|
||||
Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4
|
||||
Examples:
|
||||
rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
|
||||
rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
|
||||
|
||||
This patch didn't fix the issue:
|
||||
[PATCH 21/21] Link detect and recursive routes
|
||||
http://www.gossamer-threads.com/lists/quagga/dev/17564
|
||||
|
||||
See the example below for the route 2.2.2.2.
|
||||
|
||||
bash# route add -host 1.1.1.1 gw 127.0.0.1
|
||||
bash# route add -host 2.2.2.2 gw 1.1.1.1
|
||||
bash# netstat -nvr
|
||||
Kernel IP routing table
|
||||
Destination Gateway Genmask Flags MSS Window irtt Iface
|
||||
2.2.2.2 1.1.1.1 255.255.255.255 UGH 0 0 0 lo
|
||||
1.1.1.1 127.0.0.1 255.255.255.255 UGH 0 0 0 lo
|
||||
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
|
||||
0.0.0.0 192.168.0.2 0.0.0.0 UG 0 0 0 eth0
|
||||
bash#
|
||||
|
||||
zebra# sh ip route
|
||||
Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,
|
||||
I - ISIS, B - BGP, > - selected route, * - FIB route
|
||||
|
||||
K>* 0.0.0.0/0 via 192.168.0.2, eth0
|
||||
K>* 1.1.1.1/32 via 127.0.0.1, lo
|
||||
K * 2.2.2.2/32 via 1.1.1.1, lo inactive
|
||||
C>* 127.0.0.0/8 is directly connected, lo
|
||||
C>* 192.168.0.0/24 is directly connected, eth0
|
||||
|
||||
quagga-pimd-router# sh ip route 1.1.1.1
|
||||
Address NextHop Interface Metric Preference
|
||||
1.1.1.1 127.0.0.1 lo 0 0
|
||||
quagga-pimd-router#
|
||||
quagga-pimd-router# sh ip route 2.2.2.2
|
||||
Address NextHop Interface Metric Preference
|
||||
2.2.2.2 192.168.0.2 eth0 0 0
|
||||
quagga-pimd-router#
|
||||
|
||||
T27 DONE Implement debug command
|
||||
test pim receive assert
|
||||
See also TODO T6: (S,G) Assert state machine.
|
||||
|
||||
T28 DONE Bad IPv4 address family=02 in Join/Prune dump
|
||||
Reported by Andrew Lunn <andrew.lunn@ascom.ch>
|
||||
|
||||
# 58-byte pim v2 Join/Prune dump
|
||||
# ------------------------------
|
||||
# IPv4 address family=02 is wrong, correct IPv4 address family is 01
|
||||
# See http://www.iana.org/assignments/address-family-numbers
|
||||
#
|
||||
c8XX YY03 : ip src 200.xx.yy.3
|
||||
e000 000d : ip dst 224.0.0.13
|
||||
9404 0000 : ip router alert option 148.4.0.0
|
||||
2300 ab13 : pimv2,type=3 res=00 checksum=ab13
|
||||
0200 : upstream family=02, encoding=00
|
||||
c8XX YY08 : upstream 200.xx.yy.8
|
||||
0001 00d2 : res=00 groups=01 holdtime=00d2
|
||||
0200 0020 : group family=02, encoding=00, res=00, mask_len=20
|
||||
ef01 0101 : group address 239.1.1.1
|
||||
0001 0000 : joined=0001 pruned=0000
|
||||
0200 0020 : source family=02, encoding=00, res=00, mask_len=20
|
||||
0101 0101 : source address 1.1.1.1
|
||||
|
||||
T29 DONE Reset interface PIM-hello-sent counter when primary address changes
|
||||
See pim_ifp->pim_ifstat_hello_sent
|
||||
|
||||
RFC 4601: 4.3.1. Sending Hello Messages
|
||||
|
||||
Thus, if a router needs to send a Join/Prune or Assert message on
|
||||
an interface on which it has not yet sent a Hello message with the
|
||||
currently configured IP address, then it MUST immediately send the
|
||||
relevant Hello message without waiting for the Hello Timer to
|
||||
expire, followed by the Join/Prune or Assert message.
|
||||
|
||||
T30 DONE Run interface DR election when primary address changes
|
||||
Reported by Andrew Lunn <andrew.lunn@ascom.ch>
|
||||
See pim_if_dr_election().
|
||||
|
||||
T31 If an interface changes one of its secondary IP addresses, a Hello
|
||||
T2 If an interface changes one of its secondary IP addresses, a Hello
|
||||
message with an updated Address_List option and a non-zero
|
||||
HoldTime should be sent immediately.
|
||||
See also detect_secondary_address_change
|
||||
See also CAVEAT C15.
|
||||
See also RFC 4601: 4.3.1. Sending Hello Messages
|
||||
|
||||
T32 FIXED Detection of interface primary address changes may fail when
|
||||
there are multiple addresses.
|
||||
See also CAVEAT C14.
|
||||
|
||||
pim_find_primary_addr() should return interface primary address
|
||||
from connected list. Currently it returns the first address.
|
||||
|
||||
Zebra daemon "show int" is able to keep the primary address as
|
||||
first address.
|
||||
|
||||
T33 DONE Implement debug command: test pim receive upcall
|
||||
See also TODO T6: (S,G) Assert state machine.
|
||||
|
||||
T34 DONE assert_action_a1
|
||||
|
||||
T35 DONE Review macros depending on interface I.
|
||||
|
||||
See also: grep ,I\) pimd/*.c
|
||||
|
||||
For the case (S,G,I) check if I is either
|
||||
1) interface attached to this per-interface S,G state (don't think so)
|
||||
or
|
||||
2) an arbitrary interface (most probably)
|
||||
|
||||
For the arbitrary interface case (2), consider representing
|
||||
interface ifp as its primary address (struct in_addr ifaddr). The
|
||||
benefit is in_addr does not need to be dereferenced, so it does
|
||||
not demand protection against crashes.
|
||||
|
||||
T36 DONE React to zebra daemon link-detect up/down notification.
|
||||
pim_ifp->primary_address is managed by detect_primary_address_change()
|
||||
depending on to ifp->connected (managed by zebra_interface_address_read()).
|
||||
|
||||
T37 DONE Review list of variables which may affect pim_upstream.c
|
||||
pim_upstream_evaluate_join_desired().
|
||||
Call pim_upstream_update_join_desired() accordingly.
|
||||
|
||||
See the order of invokation:
|
||||
pim_if_dr_election(ifp);
|
||||
pim_if_update_join_desired(pim_ifp); /* depends on DR */
|
||||
pim_if_update_could_assert(ifp); /* depends on DR */
|
||||
pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
|
||||
|
||||
join_desired depends on:
|
||||
pim_ifp->primary_address
|
||||
pim_ifp->pim_dr_addr
|
||||
ch->ifassert_winner_metric
|
||||
ch->ifassert_winner
|
||||
ch->local_ifmembership
|
||||
ch->ifjoin_state
|
||||
ch->upstream->rpf.source_nexthop.mrib_metric_preference
|
||||
ch->upstream->rpf.source_nexthop.mrib_route_metric
|
||||
ch->upstream->rpf.source_nexthop.interface
|
||||
|
||||
T38 DONE Detect change in AssertTrackingDesired(S,G,I)
|
||||
|
||||
See the order of invokation:
|
||||
dr_election: none
|
||||
update_join_desired: depends on DR
|
||||
update_tracking_desired: depends on DR, join_desired
|
||||
|
||||
AssertTrackingDesired(S,G,I) depends on:
|
||||
pim_ifp->primary_address
|
||||
pim_ifp->pim_dr_addr
|
||||
ch->local_ifmembership
|
||||
ch->ifassert_winner
|
||||
ch->ifjoin_state
|
||||
ch->upstream->rpf.source_nexthop.interface
|
||||
PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags)
|
||||
|
||||
T39 DONE AssertTrackingDesired: flags is not matching evaluation
|
||||
|
||||
# show ip pim assert-internal
|
||||
CA: CouldAssert
|
||||
ECA: Evaluate CouldAssert
|
||||
ATD: AssertTrackingDesired
|
||||
eATD: Evaluate AssertTrackingDesired
|
||||
|
||||
Interface Address Source Group CA eCA ATD eATD
|
||||
eth0 192.168.1.100 1.1.1.1 239.1.1.1 no no no yes
|
||||
#
|
||||
|
||||
T40 Lightweight MLDv2
|
||||
T3 Lightweight MLDv2
|
||||
http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05
|
||||
http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt
|
||||
http://www.ietf.org/html.charters/mboned-charter.html
|
||||
|
||||
T41 DONE ssmping support
|
||||
|
||||
See also:
|
||||
http://www.venaas.no/multicast/ssmping/
|
||||
draft-ietf-mboned-ssmping-07
|
||||
http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07
|
||||
|
||||
Example:
|
||||
|
||||
debug ssmpingd
|
||||
|
||||
conf t
|
||||
ip ssmpingd 1.1.1.1
|
||||
|
||||
show ip ssmpingd
|
||||
|
||||
T42 Static igmp join fails when loading config at boot time
|
||||
T4 Static igmp join fails when loading config at boot time
|
||||
|
||||
! Wrong behavior seen at boot time:
|
||||
!
|
||||
|
@ -396,7 +42,7 @@ T42 Static igmp join fails when loading config at boot time
|
|||
eth0 200.202.112.3 2 2 0 0 0 0
|
||||
lo 127.0.0.1 1 1 0 0 0 0
|
||||
|
||||
T43 PIM Neighbor Reduction
|
||||
T5 PIM Neighbor Reduction
|
||||
https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/
|
||||
|
||||
"In a transit LAN (no directly connected source or receiver), many
|
||||
|
@ -404,19 +50,19 @@ T43 PIM Neighbor Reduction
|
|||
a procedure to reduce the amount of neighbors established over a
|
||||
transit LAN."
|
||||
|
||||
T44 Single Stream Multicast Fast Reroute (SMFR) Method
|
||||
T6 Single Stream Multicast Fast Reroute (SMFR) Method
|
||||
https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/
|
||||
|
||||
"This document proposes an IP multicast fast convergence method
|
||||
based on differentiating primary and backup PIM join."
|
||||
|
||||
T45 RFC5384 - The Join Attribute Format
|
||||
T7 RFC5384 - The Join Attribute Format
|
||||
"This document describes a modification of the Join message that
|
||||
allows a node to associate attributes with a particular tree."
|
||||
|
||||
T46 PIM Multi-Topology ID (MT-ID) Join-Attribute
|
||||
T8 PIM Multi-Topology ID (MT-ID) Join-Attribute
|
||||
http://tools.ietf.org/html/draft-cai-pim-mtid-00
|
||||
Depends on T45.
|
||||
Depends on T7.
|
||||
|
||||
"This draft introduces a new type of PIM Join Attribute used to
|
||||
encode the identity of the topology PIM uses for RPF."
|
||||
|
|
|
@ -169,6 +169,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
|
|||
api.safi = SAFI_UNICAST;
|
||||
memcpy(&api.prefix, p, sizeof(*p));
|
||||
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
|
||||
api_nh = &api.nexthops[0];
|
||||
|
|
4
tests/.gitignore
vendored
4
tests/.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import frrtest
|
||||
|
||||
class TestRingbuf(frrtest.TestExitNonzero):
|
||||
class TestRingbuf(frrtest.TestMultiOut):
|
||||
program = './test_ringbuf'
|
||||
|
||||
TestRingbuf.exit_cleanly()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -520,7 +520,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
|||
nexthop->ifindex = newhop->ifindex;
|
||||
}
|
||||
return 1;
|
||||
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) {
|
||||
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
|
||||
resolved = 0;
|
||||
for (ALL_NEXTHOPS(match->nexthop, newhop)) {
|
||||
if (!CHECK_FLAG(newhop->flags,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
|
||||
|
|
|
@ -1167,12 +1167,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:
|
||||
|
||||
|
@ -1187,7 +1187,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
|
||||
|
@ -1209,7 +1209,7 @@ static int zread_route_add(struct zserv *client, u_short length,
|
|||
break;
|
||||
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:
|
||||
memset(&vtep_ip, 0, sizeof(struct ipaddr));
|
||||
|
@ -1223,7 +1223,7 @@ static int zread_route_add(struct zserv *client, u_short length,
|
|||
|
||||
nexthop = route_entry_nexthop_ipv6_ifindex_add(
|
||||
re, &api_nh->gate.ipv6, ifindex,
|
||||
re->vrf_id);
|
||||
api_nh->vrf_id);
|
||||
|
||||
/* if this an EVPN route entry,
|
||||
* program the nh as neigh
|
||||
|
|
Loading…
Reference in a new issue