Static: Minor overhaul

The patch fixes several bugs introduced in previous changes, simplifies
the protocol by handing routes uniformly, introduces asynchronous route
processing to avoid issues with separate notifications for each next-hop
in ECMP routes, and makes reconfiguration faster by avoiding quadratic
complexity.
This commit is contained in:
Ondrej Zajicek (work) 2017-03-07 18:42:41 +01:00 committed by Jan Moskyto Matejka
parent 5ffb62dd03
commit 7126cadf80
5 changed files with 463 additions and 522 deletions

View file

@ -14,7 +14,7 @@
#include "sysdep/config.h" #include "sysdep/config.h"
#define BUFFER(type) struct { type *data; uint used, size; } #define BUFFER(type) struct { type *data; uint used, size; }
#define BUFFER_TYPE(v) typeof(* (v).data)
#define BUFFER_SIZE(v) ((v).size * sizeof(* (v).data)) #define BUFFER_SIZE(v) ((v).size * sizeof(* (v).data))
#define BUFFER_INIT(v,pool,isize) \ #define BUFFER_INIT(v,pool,isize) \
@ -46,6 +46,9 @@
#define BUFFER_FLUSH(v) ({ (v).used = 0; }) #define BUFFER_FLUSH(v) ({ (v).used = 0; })
#define BUFFER_WALK(v,n) \
for (BUFFER_TYPE(v) *_n = (v).data, n; _n < ((v).data + (v).used) && (n = *_n, 1); _n++)
#define BUFFER_SHALLOW_COPY(dst, src) \ #define BUFFER_SHALLOW_COPY(dst, src) \
({ \ ({ \
(dst).used = (src).used; \ (dst).used = (src).used; \

View file

@ -133,6 +133,25 @@ t_buffer_flush(void)
return 1; return 1;
} }
static int
t_buffer_walk(void)
{
int i;
init_buffer();
fill_expected_array();
for (i = 0; i < MAX_NUM; i++)
BUFFER_PUSH(buf) = expected[i];
i = 0;
BUFFER_WALK(buf, v)
bt_assert(v == expected[i++]);
bt_assert(i == MAX_NUM);
return 1;
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -142,6 +161,7 @@ main(int argc, char *argv[])
bt_test_suite(t_buffer_pop, "Fill whole buffer (PUSH), a half of elements POP and PUSH new elements"); bt_test_suite(t_buffer_pop, "Fill whole buffer (PUSH), a half of elements POP and PUSH new elements");
bt_test_suite(t_buffer_resize, "Init a small buffer and try overfill"); bt_test_suite(t_buffer_resize, "Init a small buffer and try overfill");
bt_test_suite(t_buffer_flush, "Fill and flush all elements"); bt_test_suite(t_buffer_flush, "Fill and flush all elements");
bt_test_suite(t_buffer_walk, "Fill and walk through buffer");
return bt_exit_value(); return bt_exit_value();
} }

View file

@ -19,15 +19,9 @@ static struct f_inst **this_srt_last_cmd;
static struct static_route * static struct static_route *
static_nexthop_new(void) static_nexthop_new(void)
{ {
struct static_route *nh; struct static_route *nh = this_srt;
if (!this_snh) if (this_snh)
{
/* First next hop */
nh = this_srt;
rem_node(&this_srt->n);
}
else
{ {
/* Additional next hop */ /* Additional next hop */
nh = cfg_allocz(sizeof(struct static_route)); nh = cfg_allocz(sizeof(struct static_route));
@ -57,7 +51,7 @@ CF_ADDTO(proto, static_proto '}')
static_proto_start: proto_start STATIC static_proto_start: proto_start STATIC
{ {
this_proto = proto_config_new(&proto_static, $1); this_proto = proto_config_new(&proto_static, $1);
static_init_config(STATIC_CFG); init_list(&STATIC_CFG->routes);
}; };
static_proto: static_proto:
@ -74,13 +68,11 @@ stat_nexthop:
this_snh = static_nexthop_new(); this_snh = static_nexthop_new();
this_snh->via = $2; this_snh->via = $2;
this_snh->iface = $3; this_snh->iface = $3;
add_tail(&STATIC_CFG->neigh_routes, &this_snh->n);
} }
| VIA TEXT { | VIA TEXT {
this_snh = static_nexthop_new(); this_snh = static_nexthop_new();
this_snh->via = IPA_NONE; this_snh->via = IPA_NONE;
this_snh->if_name = $2; this_snh->iface = if_get_by_name($2);
add_tail(&STATIC_CFG->iface_routes, &this_snh->n);
} }
| stat_nexthop MPLS label_stack { | stat_nexthop MPLS label_stack {
this_snh->label_count = $3[0]; this_snh->label_count = $3[0];
@ -102,7 +94,7 @@ stat_nexthops:
stat_route0: ROUTE net_any { stat_route0: ROUTE net_any {
this_srt = cfg_allocz(sizeof(struct static_route)); this_srt = cfg_allocz(sizeof(struct static_route));
add_tail(&STATIC_CFG->other_routes, &this_srt->n); add_tail(&STATIC_CFG->routes, &this_srt->n);
this_srt->net = $2; this_srt->net = $2;
this_srt_last_cmd = &(this_srt->cmds); this_srt_last_cmd = &(this_srt->cmds);
this_srt->mp_next = NULL; this_srt->mp_next = NULL;

File diff suppressed because it is too large Load diff

View file

@ -11,49 +11,58 @@
#include "nest/route.h" #include "nest/route.h"
#include "nest/bfd.h" #include "nest/bfd.h"
#include "lib/buffer.h"
struct static_config { struct static_config {
struct proto_config c; struct proto_config c;
list iface_routes; /* Routes to search on interface events */ list routes; /* List of static routes (struct static_route) */
list neigh_routes; /* Routes to search on neighbor events */
list other_routes; /* Non-nexthop routes */
int check_link; /* Whether iface link state is used */ int check_link; /* Whether iface link state is used */
struct rtable_config *igp_table; /* Table used for recursive next hop lookups */ struct rtable_config *igp_table; /* Table used for recursive next hop lookups */
}; };
struct static_proto {
struct proto p;
void static_init_config(struct static_config *); struct event *event; /* Event for announcing updated routes */
BUFFER(struct static_route *) marked; /* Routes marked for reannouncement */
};
struct static_route { struct static_route {
node n; node n;
struct static_route *chain; /* Next for the same neighbor */
net_addr *net; /* Network we route */ net_addr *net; /* Network we route */
int dest; /* Destination type (RTD_*) */
ip_addr via; /* Destination router */ ip_addr via; /* Destination router */
struct iface *iface; /* Destination iface, for link-local vias or device routes */ struct iface *iface; /* Destination iface, for link-local vias or device routes */
struct neighbor *neigh; struct neighbor *neigh; /* Associated neighbor entry */
byte *if_name; /* Name for device routes */ struct static_route *chain; /* Next for the same neighbor */
struct static_route *mp_next; /* Nexthops for multipath routes */
struct static_route *mp_head; /* First nexthop of this route */ struct static_route *mp_head; /* First nexthop of this route */
struct static_route *mp_next; /* Nexthops for multipath routes */
struct f_inst *cmds; /* List of commands for setting attributes */ struct f_inst *cmds; /* List of commands for setting attributes */
u32 state; /* Current state: STS_* */ byte dest; /* Destination type (RTD_*) */
int weight; /* Multipath next hop weight */ byte state; /* State of route announcement (SRS_*) */
byte active; /* Next hop is active (nbr/iface/BFD available) */
byte weight; /* Multipath next hop weight */
byte use_bfd; /* Configured to use BFD */ byte use_bfd; /* Configured to use BFD */
byte label_count; /* Number of labels in stack */ byte label_count; /* Number of labels in stack */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */
u32 *label_stack; /* Label stack if label_count > 0 */ u32 *label_stack; /* Label stack if label_count > 0 */
}; };
#define STS_INSTALLED 0x1 /*
#define STS_WANT 0x2 * Note that data fields neigh, chain, state, active and bfd_req are runtime
#define STS_FORCE 0x4 * data, not real configuration data. Must be handled carefully.
*
/* Dummy nodes (parts of multipath route) abuses masklen field for weight * Regular (i.e. dest == RTD_UNICAST) routes use static_route structure for
and if_name field for a ptr to the master (RTD_MULTIPATH) node. */ * additional next hops (fields mp_head, mp_next). Note that 'state' is for
* whole route, while 'active' is for each next hop. Also note that fields
* mp_head, mp_next, active are zero for other kinds of routes.
*/
#define RTDX_RECURSIVE 0x7f /* Phony dest value for recursive routes */ #define RTDX_RECURSIVE 0x7f /* Phony dest value for recursive routes */
#define SRS_DOWN 0 /* Route is not announced */
#define SRS_CLEAN 1 /* Route is active and announced */
#define SRS_DIRTY 2 /* Route changed since announcement */
void static_show(struct proto *); void static_show(struct proto *);
#endif #endif