From da0b589e7bbcd8177702caa925063d36e7f316ec Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 27 Sep 2022 16:13:27 +0200 Subject: [PATCH 1/3] BGP: Some fixes related to VRF and MPLS interactions - When next hop is reset to local IP, we should remove BGP label stack, as it is related to original next hop - BGP next hop or immediate next hop from one VRF should not be passed to another VRF, as they are different IP namespaces --- proto/bgp/packets.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index fc23897d..8087608a 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1112,6 +1112,10 @@ bgp_use_next_hop(struct bgp_export_state *s, eattr *a) if ((ipa_is_ip4(*nh) != bgp_channel_is_ipv4(c)) && !c->ext_next_hop) return 0; + /* Do not pass NEXT_HOP between different VRFs */ + if (p->p.vrf_set && s->src && s->src->p.vrf_set && (p->p.vrf != s->src->p.vrf)) + return 0; + /* Keep it when exported to internal peers */ if (p->is_interior && ipa_nonzero(*nh)) return 1; @@ -1141,6 +1145,10 @@ bgp_use_gateway(struct bgp_export_state *s) if ((ipa_is_ip4(ra->nh.gw) != bgp_channel_is_ipv4(c)) && !c->ext_next_hop) return 0; + /* Do not use gateway from different VRF */ + if (p->p.vrf_set && ra->nh.iface && (p->p.vrf != ra->nh.iface->master)) + return 0; + /* Use it when exported to internal peers */ if (p->is_interior) return 1; @@ -1167,6 +1175,8 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to) uint lnum = ra->nh.labels ? ra->nh.labels : 1; bgp_set_attr_data(to, s->pool, BA_MPLS_LABEL_STACK, 0, labels, lnum * 4); } + else + bgp_unset_attr(to, s->pool, BA_MPLS_LABEL_STACK); } else { @@ -1180,6 +1190,8 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to) u32 implicit_null = BGP_MPLS_NULL; bgp_set_attr_data(to, s->pool, BA_MPLS_LABEL_STACK, 0, &implicit_null, 4); } + else + bgp_unset_attr(to, s->pool, BA_MPLS_LABEL_STACK); } } From 92a856554780c262f188acb4cdcee363bf6dd1bb Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 27 Sep 2022 16:47:52 +0200 Subject: [PATCH 2/3] Filter: Add some minor functions for f_tree and EC Add some supportive functions for f_tree and EC. These functions are used by L3VPN code. --- filter/data.c | 6 +++--- filter/data.h | 5 +++++ filter/tree.c | 8 ++++++++ nest/attrs.h | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/filter/data.c b/filter/data.c index 87c438fc..56d746fd 100644 --- a/filter/data.c +++ b/filter/data.c @@ -336,7 +336,7 @@ clist_set_type(const struct f_tree *set, struct f_val *v) } } -static int +int clist_match_set(const struct adata *clist, const struct f_tree *set) { if (!clist) @@ -357,7 +357,7 @@ clist_match_set(const struct adata *clist, const struct f_tree *set) return 0; } -static int +int eclist_match_set(const struct adata *list, const struct f_tree *set) { if (!list) @@ -381,7 +381,7 @@ eclist_match_set(const struct adata *list, const struct f_tree *set) return 0; } -static int +int lclist_match_set(const struct adata *list, const struct f_tree *set) { if (!list) diff --git a/filter/data.h b/filter/data.h index c96856ce..051f0932 100644 --- a/filter/data.h +++ b/filter/data.h @@ -192,6 +192,7 @@ struct f_tree *f_new_tree(void); struct f_tree *build_tree(struct f_tree *); const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val); int same_tree(const struct f_tree *t0, const struct f_tree *t2); +int tree_node_count(const struct f_tree *t); void tree_format(const struct f_tree *t, buffer *buf); void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data); @@ -286,6 +287,10 @@ static inline int lclist_set_type(const struct f_tree *set) static inline int path_set_type(const struct f_tree *set) { return !set || set->from.type == T_INT; } +int clist_match_set(const struct adata *clist, const struct f_tree *set); +int eclist_match_set(const struct adata *list, const struct f_tree *set); +int lclist_match_set(const struct adata *list, const struct f_tree *set); + const struct adata *clist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos); const struct adata *eclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos); const struct adata *lclist_filter(struct linpool *pool, const struct adata *list, const struct f_val *set, int pos); diff --git a/filter/tree.c b/filter/tree.c index 5da86b9d..97bf7dae 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -134,6 +134,14 @@ same_tree(const struct f_tree *t1, const struct f_tree *t2) return 1; } +int +tree_node_count(const struct f_tree *t) +{ + if (t == NULL) + return 0; + + return 1 + tree_node_count(t->left) + tree_node_count(t->right); +} static void tree_node_format(const struct f_tree *t, buffer *buf) diff --git a/nest/attrs.h b/nest/attrs.h index 9412439b..fcd5ac16 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -138,6 +138,11 @@ static inline const char *ec_subtype_str(const enum ec_subtype ecs) { } } +/* Check for EC_RT subtype within different types (0-2) */ +static inline int ec_type_is_rt(uint type) +{ return (type == EC_RT) || (type == (0x0100 | EC_RT)) || (type == (0x0200 | EC_RT)); } + + /* Transitive bit (for first u32 half of EC) */ #define EC_TBIT 0x40000000 @@ -157,9 +162,13 @@ static inline u32 *int_set_get_data(const struct adata *list) static inline u32 ec_hi(u64 ec) { return ec >> 32; } static inline u32 ec_lo(u64 ec) { return ec; } + static inline u64 ec_get(const u32 *l, int i) { return (((u64) l[i]) << 32) | l[i+1]; } +static inline void ec_put(u32 *l, int i, u64 val) +{ l[i] = ec_hi(val); l[i+1] = ec_lo(val); } + /* RFC 4360 3.1. Two-Octet AS Specific Extended Community */ static inline u64 ec_as2(enum ec_subtype kind, u64 key, u64 val) { return (((u64) kind | 0x0000) << 48) | (key << 32) | val; } From 8478de8817c58af02f7aed1d621013891115a2dc Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 3 Oct 2022 18:53:21 +0200 Subject: [PATCH 3/3] Nest: Add channel config flag to distinguish new or copy It is useful to distinguish whehter channel config returned from channel_config_get() was allocated new, or existing from template. Caller may want to initialize new ones. --- nest/proto.c | 1 + nest/protocol.h | 1 + 2 files changed, 2 insertions(+) diff --git a/nest/proto.c b/nest/proto.c index 60a74964..885a0b75 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -804,6 +804,7 @@ channel_config_get(const struct channel_class *cc, const char *name, uint net_ty cf_error("Multiple %s channels", name); cf->parent = proto; + cf->copy = 1; return cf; } diff --git a/nest/protocol.h b/nest/protocol.h index 29d759ea..46744357 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -493,6 +493,7 @@ struct channel_config { u8 ra_mode; /* Mode of received route advertisements (RA_*) */ u16 preference; /* Default route preference */ u32 debug; /* Debugging flags (D_*) */ + u8 copy; /* Value from channel_config_get() is new (0) or from template (1) */ u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 rpki_reload; /* RPKI changes trigger channel reload */