Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,26 @@ EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- EC_COMP_FOREACH
- LIST_FOREACH
- LIST_FOREACH_SAFE
- RB_FOREACH
- RNODE_FOREACH_RE
- RTE_ETH_FOREACH_DEV
- RTE_ETH_FOREACH_MATCHING_DEV
- RTE_LCORE_FOREACH
- SLIST_FOREACH
- SLIST_FOREACH_SAFE
- STAILQ_FOREACH
- STAILQ_FOREACH_SAFE
- TAILQ_FOREACH
- TAILQ_FOREACH_SAFE
- rte_graph_foreach_node
- gr_api_client_stream_foreach
- gr_flags_foreach
- nexthop_type_ops_foreach
- rte_graph_foreach_node
- vec_foreach
- vec_foreach_ref
- gr_nh_flags_foreach
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^".*'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
sudo apt-get install -qy --no-install-recommends \
make gcc gdb ccache ninja-build meson git scdoc inotify-tools \
libibverbs-dev libasan8 libcmocka-dev libedit-dev libarchive-dev \
libevent-dev libmnl-dev libnuma-dev python3-pyelftools \
libevent-dev libmnl-dev libnuma-dev python3-pyelftools arping \
socat tcpdump traceroute graphviz iproute2 iputils-ping ndisc6 jq \
dnsmasq systemd-coredump abigail-tools \
"linux-modules-extra-$(uname -r)"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,13 +287,13 @@ In order to run the `smoke-tests`, `lint`, `check-patches` and `update-graph`
targets, you'll need additional packages:

```sh
dnf install gawk gdb clang-tools-extra jq codespell curl traceroute graphviz ndisc6 abidiff inotify-tools
dnf install gawk gdb clang-tools-extra iputils jq codespell curl traceroute graphviz ndisc6 abidiff inotify-tools
```

or

```sh
apt install gawk gdb clang-format jq codespell curl traceroute graphviz ndisc6 abigail-tools inotify-tools
apt install arping gawk gdb clang-format jq codespell curl traceroute graphviz ndisc6 abigail-tools inotify-tools
```

### Build
Expand Down
2 changes: 1 addition & 1 deletion api/gr_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <stdlib.h>

// Must be bumped when making non-backward compatible changes in API headers
#define GR_API_VERSION 5
#define GR_API_VERSION 6

// API request header.
struct gr_api_request {
Expand Down
5 changes: 5 additions & 0 deletions api/gr_macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <errno.h>
#include <limits.h>
#include <stdint.h>

// Get number of elements in a static array.
#define ARRAY_DIM(array) (sizeof(array) / sizeof(array[0]))
Expand Down Expand Up @@ -48,3 +49,7 @@

#define GR_SYMBOL_FORBIDDEN(func, new_func) \
sorry_##func##_is_a_banned_function_use_##new_func##_instead

#define gr_flags_foreach(f, flags) \
for (uint64_t __bit = 0, f = 1ULL; __bit < sizeof(flags) * CHAR_BIT; f = 1ULL << ++__bit) \
if (flags & f)
4 changes: 2 additions & 2 deletions cli/complete.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ int bash_complete(struct ec_node *cmdlist) {

count = 0;
comp_width = 0;
EC_COMP_FOREACH(item, cmpl, EC_COMP_FULL | EC_COMP_PARTIAL) {
EC_COMP_FOREACH (item, cmpl, EC_COMP_FULL | EC_COMP_PARTIAL) {
int w = strlen(ec_comp_item_get_str(item));
if (w > comp_width)
comp_width = w;
Expand All @@ -131,7 +131,7 @@ int bash_complete(struct ec_node *cmdlist) {
colon_prefix = last_colon - comp_word + 1;
comp_width -= colon_prefix;

EC_COMP_FOREACH(item, cmpl, EC_COMP_FULL | EC_COMP_PARTIAL) {
EC_COMP_FOREACH (item, cmpl, EC_COMP_FULL | EC_COMP_PARTIAL) {
const char *choice = ec_comp_item_get_str(item) + colon_prefix;
const char *help = find_help(item);
if (count > 1 && help != NULL) {
Expand Down
2 changes: 1 addition & 1 deletion cli/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ get_suggestions(const struct ec_node *cmdlist, const char *cmdline, unsigned *po
goto out;

struct ec_comp_item *i;
EC_COMP_FOREACH(i, c, EC_COMP_FULL) {
EC_COMP_FOREACH (i, c, EC_COMP_FULL) {
if (ec_strvec_add(sug, ec_comp_item_get_str(i)) < 0)
goto out;
}
Expand Down
772 changes: 398 additions & 374 deletions docs/graph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
159 changes: 155 additions & 4 deletions frr/rt_grout.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ static enum zebra_dplane_result grout_add_nexthop_group(struct zebra_dplane_ctx
static enum zebra_dplane_result grout_del_nexthop(uint32_t nh_id) {
gr_log_debug("nh_id %u", nh_id);

struct gr_nh_del_req req = {.missing_ok = true, .nh_id = nh_id};
struct gr_nh_del_req req = {.missing_ok = true, .nh = {.nh_id = nh_id}};

if (grout_client_send_recv(GR_NH_DEL, sizeof(req), &req, NULL) < 0)
return ZEBRA_DPLANE_REQUEST_FAILURE;
Expand Down Expand Up @@ -931,16 +931,80 @@ void grout_nexthop_group_add(struct gr_nexthop *gr_nh, bool startup) {
);
}

static void grout_neigh_notify(bool new, struct gr_nexthop *gr_nh) {
const struct gr_nexthop_info_l3 *l3;
static const struct ethaddr zero_mac = {};
struct zebra_dplane_ctx *ctx;
struct ethaddr mac;
struct ipaddr ip;

if (gr_nh->type != GR_NH_T_L3)
return;

l3 = (const struct gr_nexthop_info_l3 *)gr_nh->info;

if (l3->af != GR_AF_IP4 && l3->af != GR_AF_IP6)
return;
if (l3->flags & (GR_NH_F_LOCAL | GR_NH_F_LINK | GR_NH_F_MCAST | GR_NH_F_REMOTE))
return;
if (new && memcmp(&l3->mac, &zero_mac, sizeof(zero_mac)) == 0)
return;

memset(&ip, 0, sizeof(ip));
if (l3->af == GR_AF_IP4) {
ip.ipa_type = IPADDR_V4;
memcpy(&ip.ipaddr_v4, &l3->ipv4, sizeof(ip.ipaddr_v4));
} else {
ip.ipa_type = IPADDR_V6;
memcpy(&ip.ipaddr_v6, &l3->ipv6, sizeof(ip.ipaddr_v6));
}
memcpy(&mac, &l3->mac, sizeof(mac));

gr_log_debug(
"%s neigh iface=%u %pIA %pEA", new ? "add" : "del", gr_nh->iface_id, &ip, &mac
);

ctx = dplane_ctx_alloc();
dplane_ctx_set_op(ctx, new ? DPLANE_OP_NEIGH_INSTALL : DPLANE_OP_NEIGH_DELETE);
dplane_ctx_set_ns_id(ctx, GROUT_NS);
dplane_ctx_set_ifindex(ctx, ifindex_grout_to_frr(gr_nh->iface_id));
dplane_ctx_neigh_set_ipaddr(ctx, &ip);
dplane_ctx_neigh_set_mac(ctx, &mac);
dplane_ctx_neigh_set_ndm_state(ctx, NUD_REACHABLE);
dplane_ctx_neigh_set_ndm_family(ctx, l3->af == GR_AF_IP4 ? AF_INET : AF_INET6);
dplane_ctx_neigh_set_l2_len(ctx, ETH_ALEN);
#if CURRENT_FRR_VERSION >= MAKE_FRRVERSION(10, 6, 0)
dplane_ctx_neigh_set_is_own(ctx, false);
#else
dplane_ctx_neigh_set_is_ext(ctx, false);
#endif
dplane_ctx_neigh_set_is_router(ctx, false);
dplane_ctx_neigh_set_dp_static(ctx, false);
dplane_ctx_neigh_set_local_inactive(ctx, false);

dplane_provider_enqueue_to_zebra(ctx);
}

void grout_nexthop_change(bool new, struct gr_nexthop *gr_nh, bool startup) {
struct nexthop *nh = NULL;
afi_t afi = AFI_UNSPEC;
int family, type;

gr_log_debug("%s nh_id %u", new ? "add" : "del", gr_nh->nh_id);
gr_log_debug(
"%s nh_id %u origin %s",
new ? "add" : "del",
gr_nh->nh_id,
gr_nh_origin_name(gr_nh->origin)
);

grout_neigh_notify(new, gr_nh);

// XXX: grout is optional to have an ID for nexthop
// but in FRR, it's mandatory
if (gr_nh->origin == GR_NH_ORIGIN_NEIGH) {
gr_log_debug("dynamic neighbor learn, skip");
return;
}
if (gr_nh->nh_id == 0) {
// Nexthop IDs are optional in grout, but mandatory in FRR.
gr_log_debug("nexthop without ID, skip");
return;
}
Expand Down Expand Up @@ -1095,6 +1159,90 @@ enum zebra_dplane_result grout_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) {
return ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE;
}

static void neigh_install_nexthop(struct zebra_dplane_ctx *ctx, const struct ipaddr *addr) {
uint16_t iface_id = ifindex_frr_to_grout(dplane_ctx_get_ifindex(ctx));
const struct ethaddr *mac = dplane_ctx_neigh_get_mac(ctx);
struct gr_nexthop_info_l3 *l3;
struct gr_nh_add_req *req;
size_t len;

if (iface_id == GR_IFACE_ID_UNDEF)
return;

len = sizeof(*req) + sizeof(*l3);
req = calloc(1, len);
if (req == NULL) {
gr_log_err("calloc: %s", strerror(errno));
return;
}

req->exist_ok = true;
req->nh.type = GR_NH_T_L3;
req->nh.origin = zebra2origin(dplane_ctx_get_type(ctx));
req->nh.iface_id = iface_id;
l3 = (struct gr_nexthop_info_l3 *)req->nh.info;
l3->flags = GR_NH_F_REMOTE;

switch (addr->ipa_type) {
case IPADDR_V4:
l3->af = GR_AF_IP4;
memcpy(&l3->ipv4, &addr->ipaddr_v4, sizeof(l3->ipv4));
break;
case IPADDR_V6:
l3->af = GR_AF_IP6;
memcpy(&l3->ipv6, &addr->ipaddr_v6, sizeof(l3->ipv6));
break;
default:
free(req);
return;
}
memcpy(&l3->mac, mac, sizeof(l3->mac));

gr_log_debug("install remote nh iface=%u %pIA %pEA", iface_id, addr, mac);
grout_client_send_recv(GR_NH_ADD, len, req, NULL);
free(req);
}

static void neigh_delete_nexthop(struct zebra_dplane_ctx *ctx, const struct ipaddr *addr) {
uint16_t iface_id = ifindex_frr_to_grout(dplane_ctx_get_ifindex(ctx));
struct gr_nexthop_info_l3 *l3;
struct gr_nh_del_req *req;
size_t len;

if (iface_id == GR_IFACE_ID_UNDEF)
return;

len = sizeof(*req) + sizeof(*l3);
req = calloc(1, len);
if (req == NULL) {
gr_log_err("calloc: %s", strerror(errno));
return;
}

req->missing_ok = true;
req->nh.type = GR_NH_T_L3;
req->nh.iface_id = iface_id;
l3 = (struct gr_nexthop_info_l3 *)req->nh.info;

switch (addr->ipa_type) {
case IPADDR_V4:
l3->af = GR_AF_IP4;
memcpy(&l3->ipv4, &addr->ipaddr_v4, sizeof(l3->ipv4));
break;
case IPADDR_V6:
l3->af = GR_AF_IP6;
memcpy(&l3->ipv6, &addr->ipaddr_v6, sizeof(l3->ipv6));
break;
default:
free(req);
return;
}

gr_log_debug("delete remote nh iface=%u %pIA", iface_id, addr);
grout_client_send_recv(GR_NH_DEL, len, req, NULL);
free(req);
}

enum zebra_dplane_result grout_neigh_update_ctx(struct zebra_dplane_ctx *ctx) {
const struct ipaddr *addr = dplane_ctx_neigh_get_ipaddr(ctx);
bool add = dplane_ctx_get_op(ctx) != DPLANE_OP_NEIGH_DELETE;
Expand All @@ -1115,9 +1263,12 @@ enum zebra_dplane_result grout_neigh_update_ctx(struct zebra_dplane_ctx *ctx) {
const struct ethaddr *mac = dplane_ctx_neigh_get_mac(ctx);
gr_log_debug("cache rmac vrf=%u %pIA %pEA", vrf_id, addr, mac);
l3vni_rmac_set(vrf_id, addr, mac);
// Install a remote nexthop for ARP/ND suppression.
neigh_install_nexthop(ctx, addr);
} else {
gr_log_debug("uncache rmac vrf=%u %pIA", vrf_id, addr);
l3vni_rmac_del(vrf_id, addr);
neigh_delete_nexthop(ctx, addr);
}

return ZEBRA_DPLANE_REQUEST_SUCCESS;
Expand Down
4 changes: 2 additions & 2 deletions frr/zebra_dplane_grout.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ static void grout_sync_poll_marker(struct event *e) {
if (table) {
rn = route_node_lookup(table, &grout_sync_marker_prefix);
if (rn) {
RNODE_FOREACH_RE(rn, re) {
RNODE_FOREACH_RE (rn, re) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
continue;
if (re->tag == GROUT_SYNC_MARKER_TAG
Expand Down Expand Up @@ -944,7 +944,7 @@ static void grout_ns_reset(void) {
struct vrf *default_vrf, *vrf;
struct interface *ifp;

RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
FOR_ALL_INTERFACES(vrf, ifp) {
if_down(ifp);
}
Expand Down
1 change: 1 addition & 0 deletions modules/infra/api/gr_infra.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef enum : uint16_t {
GR_IFACE_F_PACKET_TRACE = GR_BIT16(2),
GR_IFACE_F_SNAT_STATIC = GR_BIT16(3),
GR_IFACE_F_SNAT_DYNAMIC = GR_BIT16(4),
GR_IFACE_F_NEIGH_SNOOP = GR_BIT16(5),
} gr_iface_flags_t;

// Interface state flags.
Expand Down
Loading
Loading