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
872 changes: 463 additions & 409 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.
4 changes: 2 additions & 2 deletions docs/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ custom_target(
# Individual command man pages
# The list is hardcoded since we can't run grcli during meson configuration.
grcli_commands = [
'address', 'affinity', 'conntrack', 'dnat44', 'events', 'fdb', 'graph',
'interface', 'logging', 'nexthop', 'ping', 'ping6', 'route',
'address', 'affinity', 'conntrack', 'dnat44', 'events', 'fdb', 'flood',
'graph', 'interface', 'logging', 'nexthop', 'ping', 'ping6', 'route',
'router-advert', 'snat44', 'stats', 'trace', 'traceroute', 'traceroute6',
'tunsrc',
]
Expand Down
34 changes: 30 additions & 4 deletions frr/if_grout.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

#include <gr_ip4.h>
#include <gr_ip6.h>
#include <gr_l2.h>
#include <gr_srv6.h>

#include <linux/if.h>
#include <net/if.h>
#include <zebra/interface.h>
#include <zebra/zebra_vxlan.h>
#include <zebra_dplane_grout.h>

#define GROUT_NS NS_DEFAULT

static uint64_t gr_if_flags_to_netlink(struct gr_iface *gr_if, enum zebra_link_type link_type) {
uint64_t frr_if_flags = 0;

Expand Down Expand Up @@ -43,9 +43,12 @@ void grout_link_change(struct gr_iface *gr_if, bool new, bool startup) {
enum zebra_slave_iftype slave_type = ZEBRA_IF_SLAVE_NONE;
enum zebra_link_type link_type = ZEBRA_LLT_UNKNOWN;
enum zebra_iftype zif_type = ZEBRA_IF_OTHER;
const struct gr_iface_info_bridge *gr_bridge = NULL;
const struct gr_iface_info_vxlan *gr_vxlan = NULL;
const struct gr_iface_info_vlan *gr_vlan = NULL;
const struct gr_iface_info_port *gr_port = NULL;
const struct gr_iface_info_bond *gr_bond = NULL;
ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
ifindex_t link_ifindex = IFINDEX_INTERNAL;
ifindex_t bond_ifindex = IFINDEX_INTERNAL;
const struct rte_ether_addr *mac = NULL;
Expand Down Expand Up @@ -83,6 +86,18 @@ void grout_link_change(struct gr_iface *gr_if, bool new, bool startup) {
link_type = ZEBRA_LLT_ETHER;
zif_type = ZEBRA_IF_VRF;
break;
case GR_IFACE_TYPE_BRIDGE:
gr_bridge = (const struct gr_iface_info_bridge *)&gr_if->info;
link_type = ZEBRA_LLT_ETHER;
zif_type = ZEBRA_IF_BRIDGE;
mac = &gr_bridge->mac;
break;
case GR_IFACE_TYPE_VXLAN:
gr_vxlan = (const struct gr_iface_info_vxlan *)&gr_if->info;
link_type = ZEBRA_LLT_ETHER;
zif_type = ZEBRA_IF_VXLAN;
mac = &gr_vxlan->mac;
break;
case GR_IFACE_TYPE_UNDEF:
default:
gr_log_err(
Expand Down Expand Up @@ -123,12 +138,15 @@ void grout_link_change(struct gr_iface *gr_if, bool new, bool startup) {
bond_ifindex = ifindex_grout_to_frr(gr_if->domain_id);
slave_type = ZEBRA_IF_SLAVE_BOND;
break;
case GR_IFACE_MODE_BRIDGE:
bridge_ifindex = ifindex_grout_to_frr(gr_if->domain_id);
slave_type = ZEBRA_IF_SLAVE_BRIDGE;
break;
default:
break;
}

// no bridge support in grout
dplane_ctx_set_ifp_bridge_ifindex(ctx, IFINDEX_INTERNAL);
dplane_ctx_set_ifp_bridge_ifindex(ctx, bridge_ifindex);
dplane_ctx_set_ifp_master_ifindex(ctx, IFINDEX_INTERNAL);
dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex);
dplane_ctx_set_ifp_zif_slave_type(ctx, slave_type);
Expand All @@ -150,6 +168,14 @@ void grout_link_change(struct gr_iface *gr_if, bool new, bool startup) {
vlan_info.vid = gr_vlan->vlan_id;
dplane_ctx_set_ifp_vlan_info(ctx, &vlan_info);
}
if (gr_vxlan) {
struct zebra_l2info_vxlan vi = {0};
vi.vni_info.iftype = ZEBRA_VXLAN_IF_VNI;
vi.vni_info.vni.vni = gr_vxlan->vni;
vi.ifindex_link = ifindex_grout_to_frr(gr_vxlan->encap_vrf_id);
vi.vtep_ip.s_addr = gr_vxlan->local;
dplane_ctx_set_ifp_vxlan_info(ctx, &vi);
}
} else {
dplane_ctx_set_op(ctx, DPLANE_OP_INTF_DELETE);
dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED);
Expand Down
153 changes: 153 additions & 0 deletions frr/rt_grout.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
#include "log_grout.h"
#include "rt_grout.h"

#include <gr_l2.h>
#include <gr_srv6.h>

#include <lib/srv6.h>
#include <linux/neighbour.h>
#include <zebra/rib.h>
#include <zebra/table_manager.h>
#include <zebra_dplane_grout.h>
Expand Down Expand Up @@ -844,3 +846,154 @@ void grout_nexthop_change(bool new, struct gr_nexthop *gr_nh, bool startup) {
// nexthop_free() must *NOT* be used to preserve the nh_srv6 context.
free(nh);
}

void grout_macfdb_change(const struct gr_fdb_entry *fdb, bool new) {
struct zebra_dplane_ctx *ctx = dplane_ctx_alloc();
struct ethaddr mac;

gr_log_debug(
"%s bridge=%u iface=%u mac=%pEA vlan=%u vtep=%pI4",
new ? "add" : "del",
fdb->bridge_id,
fdb->iface_id,
&fdb->mac,
fdb->vlan_id,
&fdb->vtep
);

memcpy(&mac, &fdb->mac, sizeof(mac));

// Zebra's dplane API is asymmetric for FDB entries:
//
// - DPLANE_OP_MAC_INSTALL/DELETE is the downward path (zebra pushing
// MACs to dplane providers). The result handler is a no-op.
// - DPLANE_OP_NEIGH_INSTALL/DELETE is the upward path (dplane providers
// notifying zebra of learned MACs). This goes through
// zebra_neigh_macfdb_update() which triggers EVPN type-2 routes.
//
// It is NOT a bug to use dplane_ctx_mac_set_*() with DPLANE_OP_NEIGH_*
// ops. The macinfo and neigh fields are separate union members in the
// dplane context, and zebra's own netlink provider does the same thing
// (see rt_netlink.c netlink_macfdb_change()).
dplane_ctx_set_ns_id(ctx, GROUT_NS);
dplane_ctx_set_ifindex(ctx, ifindex_grout_to_frr(fdb->iface_id));
dplane_ctx_mac_set_addr(ctx, &mac);
dplane_ctx_mac_set_nhg_id(ctx, 0);
dplane_ctx_mac_set_ndm_state(ctx, NUD_REACHABLE);
dplane_ctx_mac_set_ndm_flags(ctx, NTF_MASTER);
dplane_ctx_mac_set_dst_present(ctx, fdb->vtep != 0);
dplane_ctx_mac_set_vtep_ip(ctx, &(struct in_addr) {fdb->vtep});
dplane_ctx_mac_set_vid(ctx, fdb->vlan_id);
dplane_ctx_mac_set_dp_static(ctx, fdb->flags & GR_FDB_F_STATIC);
dplane_ctx_mac_set_local_inactive(ctx, false);
dplane_ctx_mac_set_is_sticky(ctx, false);
dplane_ctx_set_op(ctx, new ? DPLANE_OP_NEIGH_INSTALL : DPLANE_OP_NEIGH_DELETE);

dplane_provider_enqueue_to_zebra(ctx);
}

enum zebra_dplane_result grout_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) {
bool add = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL;
uint32_t req_type;
size_t len;
void *req;
int ret;

gr_log_debug(
"%s bridge=%u iface=%u mac=%pEA vlan=%u vtep=%pI4",
add ? "add" : "del",
ifindex_frr_to_grout(dplane_ctx_get_ifindex(ctx)),
ifindex_frr_to_grout(dplane_ctx_get_ifindex(ctx)),
dplane_ctx_mac_get_addr(ctx),
dplane_ctx_mac_get_vlan(ctx),
dplane_ctx_mac_get_vtep_ip(ctx)
);

len = add ? sizeof(struct gr_fdb_add_req) : sizeof(struct gr_fdb_del_req);
req = calloc(1, len);
if (req == NULL) {
gr_log_err("failed to allocate memory");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (add) {
struct gr_fdb_add_req *add = req;
add->exist_ok = true;
add->fdb.iface_id = ifindex_frr_to_grout(dplane_ctx_get_ifindex(ctx));
add->fdb.bridge_id = ifindex_frr_to_grout(dplane_ctx_mac_get_br_ifindex(ctx));
add->fdb.vlan_id = dplane_ctx_mac_get_vlan(ctx);
add->fdb.flags = GR_FDB_F_EXTERN;
if (dplane_ctx_mac_get_dp_static(ctx))
add->fdb.flags |= GR_FDB_F_STATIC;
memcpy(&add->fdb.mac, dplane_ctx_mac_get_addr(ctx), sizeof(add->fdb.mac));
add->fdb.vtep = dplane_ctx_mac_get_vtep_ip(ctx)->s_addr;
req_type = GR_FDB_ADD;
} else {
struct gr_fdb_del_req *del = req;
del->missing_ok = true;
del->bridge_id = ifindex_frr_to_grout(dplane_ctx_mac_get_br_ifindex(ctx));
del->vlan_id = dplane_ctx_mac_get_vlan(ctx);
memcpy(&del->mac, dplane_ctx_mac_get_addr(ctx), sizeof(del->mac));
req_type = GR_FDB_DEL;
}

ret = grout_client_send_recv(req_type, len, req, NULL);

free(req);

return ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE;
}

enum zebra_dplane_result grout_vxlan_flood_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_VTEP_ADD;
struct gr_flood_entry *entry;
uint32_t req_type;
size_t len;
void *req;
int ret;

gr_log_debug(
"%s %pIA vni=%u vrf=%u",
add ? "add" : "del",
addr,
dplane_ctx_neigh_get_vni(ctx),
vrf_frr_to_grout(dplane_ctx_get_vrf(ctx))
);

if (addr->ipa_type != IPADDR_V4) {
gr_log_err("IPv6 flood list entries are not supported");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

len = add ? sizeof(struct gr_flood_add_req) : sizeof(struct gr_flood_del_req);

req = calloc(1, len);
if (req == NULL) {
gr_log_err("failed to allocate memory");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (add) {
struct gr_flood_add_req *a = req;
entry = &a->entry;
a->exist_ok = true;
req_type = GR_FLOOD_ADD;
} else {
struct gr_flood_del_req *d = req;
entry = &d->entry;
d->missing_ok = true;
req_type = GR_FLOOD_DEL;
}

entry->type = GR_FLOOD_T_VTEP;
entry->vrf_id = vrf_frr_to_grout(dplane_ctx_get_vrf(ctx));
entry->vtep.vni = dplane_ctx_neigh_get_vni(ctx);
entry->vtep.addr = addr->ipaddr_v4.s_addr;

ret = grout_client_send_recv(req_type, len, req, NULL);

free(req);

return ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE;
}
5 changes: 5 additions & 0 deletions frr/rt_grout.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <gr_ip4.h>
#include <gr_ip6.h>
#include <gr_l2.h>

#include <zebra/zebra_dplane.h>

Expand All @@ -13,3 +14,7 @@ void grout_route6_change(bool new, struct gr_ip6_route *gr_r6);
enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx);
enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx);
void grout_nexthop_change(bool new, struct gr_nexthop *gr_nh, bool startup);

void grout_macfdb_change(const struct gr_fdb_entry *fdb, bool new);
enum zebra_dplane_result grout_macfdb_update_ctx(struct zebra_dplane_ctx *ctx);
enum zebra_dplane_result grout_vxlan_flood_update_ctx(struct zebra_dplane_ctx *ctx);
Loading