Commit 8d9eef17 authored by Ondrej Zajicek's avatar Ondrej Zajicek
Browse files

BGP multipath support

Kernel option 'merge paths' allows to merge routes exported to kernel
protocol (currently BGP and static routes) to multipath routes.
parent db027a41
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -2227,6 +2227,18 @@ limitations can be overcome using another routing table and the pipe protocol.
	a graceful restart recovery is active, the Kernel protocol will defer
	synchronization of routing tables until the end of the recovery. Note
	that import of kernel routes to BIRD is not affected.

	<tag>merge paths <M>switch</M> [limit <M>number</M>]</tag>
	Usually, only best routes are exported to the kernel protocol. With path
	merging enabled, both best routes and equivalent non-best routes are
	merged during export to generate one ECMP (equal-cost multipath) route
	for each network. This is useful e.g. for BGP multipath. Note that best
	routes are still pivotal for route export (responsible for most
	properties of resulting ECMP routes), while exported non-best routes are
	responsible just for additional multipath next hops. This option also
	allows to specify a limit on maximal number of nexthops in one route. By
	default, multipath merging is disabled. If enabled, default value of the
	limit is 16.
</descrip>

<sect1>Attributes
+16 −20
Original line number Diff line number Diff line
@@ -471,26 +471,22 @@ static inline void f_rte_cow(void)
static void
f_rta_cow(void)
{
  if ((*f_rte)->attrs->aflags & RTAF_CACHED) {
  if (!rta_is_cached((*f_rte)->attrs))
    return;

  /* Prepare to modify rte */
  f_rte_cow();

    /* Store old rta to free it later */
  /* Store old rta to free it later, it stores reference from rte_cow() */
  f_old_rta = (*f_rte)->attrs;

  /*
     * Alloc new rta, do shallow copy and update rte. Fields eattrs
     * and nexthops of rta are shared with f_old_rta (they will be
     * copied when the cached rta will be obtained at the end of
     * f_run()), also the lock of hostentry is inherited (we suppose
     * hostentry is not changed by filters).
   * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
   * with f_old_rta (they will be copied when the cached rta will be obtained
   * at the end of f_run()), also the lock of hostentry is inherited (we
   * suppose hostentry is not changed by filters).
   */
    rta *ra = lp_alloc(f_pool, sizeof(rta));
    memcpy(ra, f_old_rta, sizeof(rta));
    ra->aflags = 0;
    (*f_rte)->attrs = ra;
  }
  (*f_rte)->attrs = rta_do_cow((*f_rte)->attrs, f_pool);
}

static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#endif

#define ABS(a)   ((a)>=0 ? (a) : -(a))
#define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))


+3 −0
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ struct proto {
  byte gr_wait;				/* Route export to protocol is postponed until graceful restart */
  byte down_sched;			/* Shutdown is scheduled for later (PDS_*) */
  byte down_code;			/* Reason for shutdown (PDC_* codes) */
  byte merge_limit;			/* Maximal number of nexthops for RA_MERGED */
  u32 hash_key;				/* Random key used for hashing of neighbors */
  bird_clock_t last_state_change;	/* Time of last state transition */
  char *last_state_name_announced;	/* Last state name we've announced to the user */
@@ -200,6 +201,7 @@ struct proto {
   *	   rte_recalculate Called at the beginning of the best route selection
   *	   rte_better	Compare two rte's and decide which one is better (1=first, 0=second).
   *       rte_same	Compare two rte's and decide whether they are identical (1=yes, 0=no).
   *       rte_mergable	Compare two rte's and decide whether they could be merged (1=yes, 0=no).
   *	   rte_insert	Called whenever a rte is inserted to a routing table.
   *	   rte_remove	Called whenever a rte is removed from the routing table.
   */
@@ -207,6 +209,7 @@ struct proto {
  int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
  int (*rte_better)(struct rte *, struct rte *);
  int (*rte_same)(struct rte *, struct rte *);
  int (*rte_mergable)(struct rte *, struct rte *);
  void (*rte_insert)(struct network *, struct rte *);
  void (*rte_remove)(struct network *, struct rte *);

+11 −0
Original line number Diff line number Diff line
@@ -240,6 +240,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#define RA_OPTIMAL	1		/* Announcement of optimal route change */
#define RA_ACCEPTED	2		/* Announcement of first accepted route */
#define RA_ANY		3		/* Announcement of any route change */
#define RA_MERGED	4		/* Announcement of optimal route merged with next ones */

/* Return value of import_control() callback */
#define RIC_ACCEPT	1		/* Accepted by protocol */
@@ -263,12 +264,14 @@ void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *s
static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); }
void rte_discard(rtable *tab, rte *old);
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, int silent);
void rt_refresh_begin(rtable *t, struct announce_hook *ah);
void rt_refresh_end(rtable *t, struct announce_hook *ah);
void rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);
static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
rte *rte_cow_rta(rte *r, linpool *lp);
void rt_dump(rtable *);
void rt_dump_all(void);
int rt_feed_baby(struct proto *p);
@@ -388,6 +391,12 @@ typedef struct rta {
#define IGP_METRIC_UNKNOWN 0x80000000	/* Default igp_metric used when no other
					   protocol-specific metric is availabe */


/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
static inline int rte_is_reachable(rte *r)
{ uint d = r->attrs->dest; return (d == RTD_ROUTER) || (d == RTD_DEVICE) || (d == RTD_MULTIPATH); }


/*
 *	Extended Route Attributes
 */
@@ -490,6 +499,8 @@ static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
void rta__free(rta *r);
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
rta *rta_do_cow(rta *o, linpool *lp);
static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta_do_cow(r, lp) : r; }
void rta_dump(rta *);
void rta_dump_all(void);
void rta_show(struct cli *, rta *, ea_list *);
Loading