* rte_remove Called whenever a rte is removed from the routing table.
*/
- int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
- int (*rte_better)(struct rte *, struct rte *);
int (*rte_mergable)(struct rte *, struct rte *);
struct rte * (*rte_modify)(struct rte *, struct linpool *);
void (*rte_insert)(struct network *, struct rte *);
#define EA_MPLS_POLICY EA_CODE(PROTOCOL_NONE, 2)
#define EA_MPLS_CLASS EA_CODE(PROTOCOL_NONE, 3)
#define EA_ASPA_PROVIDERS EA_CODE(PROTOCOL_NONE, 4)
+#define EA_ROUTE_CONTEXT EA_CODE(PROTOCOL_NONE, 5)
#define EA_CODE_MASK 0xffff
#define EA_CUSTOM_BIT 0x8000
#define EAF_TYPE_STRING 0x16 /* Text string */
#define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */
#define EAF_VAR_LENGTH 0x02 /* Attribute length is variable (part of type spec) */
-#define EAF_PROTO_ATTR_PTR 0x18 /* Pointer to bgp_proto_attributes */
typedef struct adata {
uint length; /* Length of data */
ea_set_attr(to, pool, id, flags, type, (uintptr_t) a);
}
+struct rte_context {
+ uint proto_class; /* Actually enum protocol_class but we can't refer to it here */
+ uint (*format)(const struct rte_context *, byte *buf);
+ int (*rte_recalculate)(const struct rte_context *, struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
+ int (*rte_better)(const struct rte_context *, struct rte *, struct rte *);
+};
+
+struct rte_ctx_adata {
+ adata ad;
+ struct rte_context *ctx;
+};
+
+const struct rte_context *rte_get_context(const rte *r);
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
*buf += int_set_format(a->u.ptr, ISF_NUMBERS, -1, *buf, end - *buf);
return GA_FULL;
+ case EA_ROUTE_CONTEXT:
+ {
+ struct rte_ctx_adata *rcad = SKIP_BACK(struct rte_ctx_adata, ad, a->u.ptr);
+ if (!rcad->ctx->format)
+ return GA_HIDDEN;
+
+ *buf += bsprintf(*buf, "route_context");
+ *(*buf)++ = ':';
+ *(*buf)++ = ' ';
+ *buf += rcad->ctx->format(rcad->ctx, *buf);
+ return GA_FULL;
+ }
+
default:
return GA_UNKNOWN;
}
static int /* Actually better or at least as good as */
rte_better(rte *new, rte *old)
{
- int (*better)(rte *, rte *);
-
if (!rte_is_valid(old))
return 1;
if (!rte_is_valid(new))
*/
return new->src->proto->proto > old->src->proto->proto;
}
- if (better = new->src->proto->rte_better)
- return better(new, old);
+
+ const struct rte_context *ctx = rte_get_context(new);
+ if (ctx && ctx->rte_better)
+ return ctx->rte_better(ctx, new, old);
+
return 0;
}
/* If routes are not sorted, find the best route and move it on
the first position. There are several optimized cases. */
- if (src->proto->rte_recalculate && src->proto->rte_recalculate(table, net, new, old, old_best))
+ const struct rte_context *ctx = rte_get_context(new);
+ if (ctx && ctx->rte_recalculate && ctx->rte_recalculate(ctx, table, net, new, old, old_best))
goto do_recalculate;
- if (new && rte_better(new, old_best))
+ if (new && rte_better(new, old_best))
{
/* The first case - the new route is cleary optimal,
we link it at the first position */
/* Call a pre-comparison hook */
/* Not really an efficient way to compute this */
- if (e->src->proto->rte_recalculate)
- e->src->proto->rte_recalculate(tab, n, new, e, NULL);
+ const struct rte_context *ctx = rte_get_context(e);
+ if (ctx && ctx->rte_recalculate)
+ ctx->rte_recalculate(ctx, tab, n, new, e, NULL);
if (e != old_best)
rte_free_quick(e);
return IGP_METRIC_UNKNOWN;
}
+const struct rte_context *
+rte_get_context(const rte *r)
+{
+ if (r == NULL)
+ return NULL;
+ const eattr *a = ea_find(r->attrs->eattrs, EA_ROUTE_CONTEXT);
+ const adata *ad = a ? a->u.ptr : NULL;
+ const struct rte_ctx_adata *rca = ad ? SKIP_BACK(const struct rte_ctx_adata, ad, ad) : NULL;
+ return rca ? rca->ctx : NULL;
+}
+
static int
rt_update_hostentry(rtable *tab, struct hostentry *he)
{
}
static int
-babel_rte_better(struct rte *new, struct rte *old)
+babel_rte_better(const struct rte_context *ctx UNUSED, struct rte *new, struct rte *old)
{
uint new_metric = ea_get_int(new->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY);
uint old_metric = ea_get_int(old->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY);
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
P->preexport = babel_preexport;
- P->rte_better = babel_rte_better;
P->rte_igp_metric = babel_rte_igp_metric;
+ p->rte_ctx.proto_class = PROTOCOL_BABEL;
+ p->rte_ctx.rte_better = babel_rte_better;
+
return P;
}
struct babel_proto {
struct proto p;
+ struct rte_context rte_ctx;
+
timer *timer;
struct fib ip4_rtable;
struct fib ip6_rtable;
int as_length = s->as4_session ? 4 : 2;
int as_sets = s->allow_as_sets;
struct bgp_proto_attributes *proto_attrs = s->proto_attrs;
+ if (!proto_attrs)
+ return;
+
int as_confed = proto_attrs->confederation && proto_attrs->is_interior;
char err[128];
return 0;
}
-static int
-bgp_encode_proto_attrs(struct bgp_write_state *s UNUSED, eattr *a UNUSED, byte *buf UNUSED, uint size UNUSED)
-{
- return 0;
-}
-
-static void
-bgp_decode_proto_attrs(struct bgp_parse_state *s UNUSED, uint code UNUSED, uint flags UNUSED, byte *data UNUSED, uint len UNUSED, ea_list **to UNUSED)
-{
- return;
-}
-
static void
bgp_decode_mpls_label_stack(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data UNUSED, uint len UNUSED, ea_list **to UNUSED)
{
.encode = bgp_encode_u32,
.decode = bgp_decode_otc,
},
- [BA_PROTO_ATTRS] = {
- .name = "bgp proto attrs",
- .type = EAF_PROTO_ATTR_PTR,
- .flags = BAF_OPERATIONAL,
- .encode = bgp_encode_proto_attrs,
- .decode = bgp_decode_proto_attrs,
- },
[BA_MPLS_LABEL_STACK] = {
.name = "mpls_label_stack",
.type = EAF_TYPE_INT_SET,
return as;
/* If AS_PATH is not defined, we treat rte as locally originated */
- struct bgp_proto_attributes *p = (struct bgp_proto_attributes *) ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_PROTO_ATTRS))->u.ptr;
+ struct bgp_proto_attributes *p = (struct bgp_proto_attributes *) ea_find(r->attrs->eattrs, EA_ROUTE_CONTEXT)->u.ptr;
return p->confederation ?: p->local_as;
}
}
int
-bgp_rte_better(rte *new, rte *old)
+bgp_rte_better(const struct rte_context *ctx, rte *new, rte *old)
{
- struct bgp_proto_attributes *new_bgp = (struct bgp_proto_attributes *) ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_PROTO_ATTRS))->u.ptr;
- struct bgp_proto_attributes *old_bgp = (struct bgp_proto_attributes *) ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_PROTO_ATTRS))->u.ptr;
+ const struct bgp_proto_attributes *new_bgp = SKIP_BACK(const struct bgp_proto_attributes, bgp_rte_ctx, ctx);
+ const struct bgp_proto_attributes *old_bgp = bgp_get_route_context(old);
+
+ ASSERT_DIE(old_bgp); /* This means that old is actually really a bgp route */
+
eattr *x, *y;
u32 n, o;
int
bgp_rte_mergable(rte *pri, rte *sec)
{
- struct bgp_proto_attributes *pri_bgp = (struct bgp_proto_attributes *) ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_PROTO_ATTRS))->u.ptr;
- struct bgp_proto_attributes *sec_bgp = (struct bgp_proto_attributes *) ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_PROTO_ATTRS))->u.ptr;
+ struct bgp_proto_attributes *pri_bgp = (struct bgp_proto_attributes *) ea_find(pri->attrs->eattrs, EA_ROUTE_CONTEXT)->u.ptr;
+ struct bgp_proto_attributes *sec_bgp = (struct bgp_proto_attributes *) ea_find(sec->attrs->eattrs, EA_ROUTE_CONTEXT)->u.ptr;
eattr *x, *y;
u32 p, s;
}
static inline int
-use_deterministic_med(rte *r)
+use_deterministic_med(const rte *r)
{
- struct bgp_proto_attributes *pa = (struct bgp_proto_attributes *) ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_PROTO_ATTRS))->u.ptr;
- return (pa->routes_proto == BGP_ROUTE) && pa->deterministic_med;
+ const struct bgp_proto_attributes *pa = bgp_get_route_context(r);
+ return pa && pa->deterministic_med;
}
int
-bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
+bgp_rte_recalculate(const struct rte_context *ctx, rtable *table, net *net, rte *new, rte *old, rte *old_best)
{
rte *r, *s;
rte *key = new ? new : old;
if (new && old && !same_group(old, lpref, lasn))
{
int i1, i2;
- i1 = bgp_rte_recalculate(table, net, NULL, old, old_best);
- i2 = bgp_rte_recalculate(table, net, new, NULL, old_best);
+ i1 = bgp_rte_recalculate(ctx, table, net, NULL, old, old_best);
+ i2 = bgp_rte_recalculate(ctx, table, net, new, NULL, old_best);
return i1 || i2;
}
old->pflags |= BGP_REF_SUPPRESSED;
/* The fast case - replace not best with worse (or remove not best) */
- if (old_suppressed && !(new && bgp_rte_better(new, old)))
+ if (old_suppressed && !(new && bgp_rte_better(ctx, new, old)))
return 0;
}
if (use_deterministic_med(s) && same_group(s, lpref, lasn))
{
s->pflags |= BGP_REF_SUPPRESSED;
- if (!r || bgp_rte_better(s, r))
+ if (!r || bgp_rte_better(ctx, s, r))
r = s;
}
P->reload_routes = bgp_reload_routes;
P->feed_begin = bgp_feed_begin;
P->feed_end = bgp_feed_end;
- P->rte_better = bgp_rte_better;
P->rte_mergable = bgp_rte_mergable;
- P->rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
P->rte_modify = bgp_rte_modify_stale;
P->rte_igp_metric = bgp_rte_igp_metric;
+ p->proto_attrs.bgp_rte_ctx.proto_class = PROTOCOL_BGP;
+ p->proto_attrs.bgp_rte_ctx.rte_better = bgp_rte_better;
+ p->proto_attrs.bgp_rte_ctx.rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
+
p->cf = cf;
- p->routes_proto = BGP_ROUTE;
p->is_internal = (cf->local_as == cf->remote_as);
p->is_interior = p->is_internal || cf->confederation_member;
p->rs_client = cf->rs_client;
uint hold_time, keepalive_time, send_hold_time; /* Times calculated from my and neighbor's requirements */
};
-enum route_proto {
- BGP_ROUTE = 1,
-};
-
-#define BGP_PROTO_ATTRIBUTES \
- enum route_proto routes_proto; /* protocol enum (pointer to bgp_proto_attributes is given to route eattrs) */ \
+#define BGP_ROUTE_CONTEXT \
+ struct rte_context bgp_rte_ctx; /* Type common header */ \
u32 local_as, remote_as; \
ip_addr local_ip, remote_ip; \
u32 local_id; /* BGP identifier of this router */ \
/* from conf */ \
BGP_ROUTE_ATTRIBUTES\
-struct bgp_proto_attributes { BGP_PROTO_ATTRIBUTES };
+struct bgp_proto_attributes { BGP_ROUTE_CONTEXT };
struct bgp_proto {
struct proto p;
const char *hostname; /* Hostname for this BGP protocol */
union {
struct bgp_proto_attributes proto_attrs;
- struct { BGP_PROTO_ATTRIBUTES; };
+ struct { BGP_ROUTE_CONTEXT; };
};
u32 public_as; /* Externally visible ASN (local_as or confederation id) */
u8 start_state; /* Substates that partitions BS_START */
/* attrs.c */
+static inline const struct bgp_proto_attributes *
+bgp_get_route_context(const rte *r)
+{
+ const struct rte_context *ctx = rte_get_context(r);
+ return (ctx && (ctx->proto_class == PROTOCOL_BGP)) ?
+ SKIP_BACK(struct bgp_proto_attributes, bgp_rte_ctx, ctx) : NULL;
+}
+
static inline eattr *
bgp_find_attr(ea_list *attrs, uint code)
{
void bgp_free_prefix_table(struct bgp_channel *c);
void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
-int bgp_rte_better(struct rte *, struct rte *);
+int bgp_rte_better(const struct rte_context *, struct rte *, struct rte *);
int bgp_rte_mergable(rte *pri, rte *sec);
-int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
+int bgp_rte_recalculate(const struct rte_context *, rtable *table, net *net, rte *new, rte *old, rte *old_best);
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
#define BAF_TRANSITIVE 0x40
#define BAF_PARTIAL 0x20
#define BAF_EXT_LEN 0x10
-#define BAF_OPERATIONAL 0x100
#define BAF_DECODE_FLAGS 0x0100 /* Private flag - attribute flags are handled by the decode hook */
#define BA_AIGP 0x1a /* RFC 7311 */
#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */
#define BA_ONLY_TO_CUSTOMER 0x23 /* RFC 9234 */
-#define BA_PROTO_ATTRS 0x24 /* BGP_PROTO_ATTRIBUTES */
/* Bird's private internal BGP attributes */
#define BA_MPLS_LABEL_STACK 0xfe /* MPLS label stack transfer attribute */
else
*ea = NULL;
- bgp_set_attr_ptr(ea, s->pool, BA_PROTO_ATTRS, 0, (adata*) s->proto_attrs);
+ struct rte_ctx_adata *rcad = lp_allocz(s->pool, sizeof *rcad);
+ rcad->ad.length = sizeof *rcad - sizeof rcad->ad;
+ rcad->ctx = &s->proto_attrs->bgp_rte_ctx;
+ ea_set_attr_ptr(ea, s->pool, EA_ROUTE_CONTEXT, 0, EAF_TYPE_OPAQUE, &rcad->ad);
/* Check for End-of-RIB marker */
if (!s->attr_len && !s->ip_unreach_len && !s->ip_reach_len)
}
static int
-l3vpn_rte_better(rte *new, rte *old)
+l3vpn_rte_better(const struct rte_context * rtx UNUSED, rte *new, rte *old)
{
/* This is hack, we should have full BGP-style comparison */
return l3vpn_metric(new) < l3vpn_metric(old);
P->rt_notify = l3vpn_rt_notify;
P->preexport = l3vpn_preexport;
P->reload_routes = l3vpn_reload_routes;
- P->rte_better = l3vpn_rte_better;
+ p->rte_ctx.rte_better = l3vpn_rte_better;
return P;
}
struct l3vpn_proto {
struct proto p;
+ struct rte_context rte_ctx;
struct channel *ip4_channel;
struct channel *ip6_channel;
struct channel *vpn4_channel;
struct proto p;
union {
struct rte_class_config rte_class;
- struct { BGP_PROTO_ATTRIBUTES };
+ struct { BGP_ROUTE_CONTEXT };
};
struct mrt_table_dump_state *table_dump;
static int ospf_preexport(struct channel *P, rte *new);
static void ospf_reload_routes(struct channel *C);
-static int ospf_rte_better(struct rte *new, struct rte *old);
+static int ospf_rte_better(const struct rte_context * rcx UNUSED, struct rte *new, struct rte *old);
static u32 ospf_rte_igp_metric(struct rte *rt);
static void ospf_disp(timer *timer);
P->reload_routes = ospf_reload_routes;
P->feed_begin = ospf_feed_begin;
P->feed_end = ospf_feed_end;
- P->rte_better = ospf_rte_better;
P->rte_igp_metric = ospf_rte_igp_metric;
+ struct ospf_proto *p = (void *) P;
+ p->rte_ctx.rte_better = ospf_rte_better;
return P;
}
/* If new is better return 1 */
static int
-ospf_rte_better(struct rte *new, struct rte *old)
+ospf_rte_better(const struct rte_context * rcx UNUSED, struct rte *new, struct rte *old)
{
u32 new_metric1 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
struct ospf_proto
{
struct proto p;
+ struct rte_context rte_ctx;
timer *disp_timer; /* OSPF proto dispatcher */
uint tick;
struct top_graph *gr; /* LSA graph */
}
static int
-rip_rte_better(struct rte *new, struct rte *old)
+rip_rte_better(const struct rte_context * rtx UNUSED, struct rte *new, struct rte *old)
{
return rip_rte_igp_metric(new) < rip_rte_igp_metric(old);
}
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
P->reload_routes = rip_reload_routes;
- P->rte_better = rip_rte_better;
P->rte_igp_metric = rip_rte_igp_metric;
+ struct rip_proto *p = (void *) P;
+ p->rte_ctx.rte_better = rip_rte_better;
return P;
}
struct rip_proto
{
struct proto p;
+ struct rte_context rte_ctx;
struct fib rtable; /* Internal routing table */
list iface_list; /* List of interfaces (struct rip_iface) */
slab *rte_slab; /* Slab for internal routes (struct rip_rte) */
}
static int
-static_rte_better(rte *new, rte *old)
+static_rte_better(const struct rte_context * rtx UNUSED, rte *new, rte *old)
{
u32 n = ea_get_int(new->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
u32 o = ea_get_int(old->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
P->neigh_notify = static_neigh_notify;
P->reload_routes = static_reload_routes;
- P->rte_better = static_rte_better;
+ p->rte_ctx.rte_better = static_rte_better;
P->rte_mergable = static_rte_mergable;
if (cf->igp_table_ip4)
struct static_proto {
struct proto p;
+ struct rte_context rte_ctx;
struct event *event; /* Event for announcing updated routes */
BUFFER_(struct static_route *) marked; /* Routes marked for reannouncement */
int marked_all; /* All routes are marked */