forked from Mirror/frr
zebra: deduplicate nexthops
There exists situations where it is possible to have duplicate nexthops passed from a higher level protocol into zebra. This code notices this duplication of nexthops and marks the duplicates as DUPLICATE so we don't attempt to install it into the kernel. This is important on *BSD as I understand it because passing duplicate nexthops will cause the route to be rejected. Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
953d97fc4a
commit
25b9cb0cc8
|
@ -71,6 +71,39 @@ int nexthop_same_no_recurse(const struct nexthop *next1,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nexthop_same_firsthop (struct nexthop *next1, struct nexthop *next2)
|
||||
{
|
||||
int type1 = NEXTHOP_FIRSTHOPTYPE(next1->type);
|
||||
int type2 = NEXTHOP_FIRSTHOPTYPE(next2->type);
|
||||
|
||||
if (type1 != type2)
|
||||
return 0;
|
||||
switch (type1)
|
||||
{
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
|
||||
return 0;
|
||||
if (next1->ifindex != next2->ifindex)
|
||||
return 0;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
if (next1->ifindex != next2->ifindex)
|
||||
return 0;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
|
||||
return 0;
|
||||
if (next1->ifindex != next2->ifindex)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* nexthop_type_to_str
|
||||
*/
|
||||
|
|
|
@ -50,6 +50,11 @@ enum blackhole_type {
|
|||
BLACKHOLE_ADMINPROHIB,
|
||||
};
|
||||
|
||||
/* IPV[46] -> IPV[46]_IFINDEX */
|
||||
#define NEXTHOP_FIRSTHOPTYPE(type) \
|
||||
((type) == NEXTHOP_TYPE_IFINDEX || (type) == NEXTHOP_TYPE_BLACKHOLE) \
|
||||
? (type) : ((type) | 1)
|
||||
|
||||
/* Nexthop label structure. */
|
||||
struct nexthop_label {
|
||||
u_int8_t num_labels;
|
||||
|
@ -74,6 +79,10 @@ struct nexthop {
|
|||
#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
|
||||
#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */
|
||||
#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */
|
||||
#define NEXTHOP_FLAG_DUPLICATE (1 << 6) /* nexthop duplicates another active one */
|
||||
#define NEXTHOP_IS_ACTIVE(flags) \
|
||||
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
|
||||
&& !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
|
||||
|
||||
/* Nexthop address */
|
||||
union {
|
||||
|
@ -141,6 +150,7 @@ extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type);
|
|||
extern int nexthop_same_no_recurse(const struct nexthop *next1,
|
||||
const struct nexthop *next2);
|
||||
extern int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2);
|
||||
extern int nexthop_same_firsthop (struct nexthop *next1, struct nexthop *next2);
|
||||
|
||||
extern const char *nexthop2str(struct nexthop *nexthop, char *str, int size);
|
||||
extern struct nexthop *nexthop_next(struct nexthop *nexthop);
|
||||
|
|
|
@ -1383,7 +1383,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
|
|||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
continue;
|
||||
if (cmd == RTM_NEWROUTE
|
||||
&& !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
&& !NEXTHOP_IS_ACTIVE(nexthop->flags))
|
||||
continue;
|
||||
if (cmd == RTM_DELROUTE
|
||||
&& !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||
|
@ -1438,7 +1438,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
|
|||
}
|
||||
|
||||
if ((cmd == RTM_NEWROUTE
|
||||
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
&& NEXTHOP_IS_ACTIVE(nexthop->flags))
|
||||
|| (cmd == RTM_DELROUTE
|
||||
&& CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_FIB))) {
|
||||
|
@ -1521,7 +1521,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
|
|||
}
|
||||
|
||||
if ((cmd == RTM_NEWROUTE
|
||||
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
&& NEXTHOP_IS_ACTIVE(nexthop->flags))
|
||||
|| (cmd == RTM_DELROUTE
|
||||
&& CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_FIB))) {
|
||||
|
|
|
@ -136,7 +136,7 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re)
|
|||
* other than ADD and DELETE?
|
||||
*/
|
||||
if ((cmd == RTM_ADD
|
||||
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
&& NEXTHOP_IS_ACTIVE(nexthop->flags))
|
||||
|| (cmd == RTM_DELETE
|
||||
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) {
|
||||
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
||||
|
@ -314,7 +314,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re)
|
|||
gate = 0;
|
||||
|
||||
if ((cmd == RTM_ADD
|
||||
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
&& NEXTHOP_IS_ACTIVE(nexthop->flags))
|
||||
|| (cmd == RTM_DELETE
|
||||
#if 0
|
||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||
|
|
|
@ -1000,8 +1000,24 @@ int rib_install_kernel(struct route_node *rn, struct route_entry *re,
|
|||
for (ALL_NEXTHOPS(re->nexthop, nexthop))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||
return ret;
|
||||
} else {
|
||||
struct nexthop *prev;
|
||||
|
||||
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
|
||||
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
|
||||
for (ALL_NEXTHOPS(re->nexthop, prev)) {
|
||||
if (prev == nexthop)
|
||||
break;
|
||||
if (nexthop_same_firsthop (nexthop, prev))
|
||||
{
|
||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make sure we update the FPM any time we send new information to
|
||||
* the kernel.
|
||||
|
|
Loading…
Reference in a new issue