Skip to content

Instantly share code, notes, and snippets.

@paigeadelethompson
Created May 7, 2025 19:23
Show Gist options
  • Save paigeadelethompson/5410597d92ce5c8be1cbdb48207ba473 to your computer and use it in GitHub Desktop.
Save paigeadelethompson/5410597d92ce5c8be1cbdb48207ba473 to your computer and use it in GitHub Desktop.
VRF experiment for FreeBSD
/*
* Copyright (c) 2023 Your Name
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* VRF (Virtual Routing and Forwarding) network interface for FreeBSD
* This interface acts as a layer 3 bridge that auto-assigns interfaces
* to specific FIBs (Forwarding Information Bases) they're associated with.
*/
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/rmlock.h>
#include <sys/sx.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
#include <net/if_clone.h>
#include <net/if_dl.h>
#include <net/vnet.h>
#include <net/route.h>
#include <net/pfil.h>
#include <net/netisr.h>
#include <net/ethernet.h>
#include <net/bpf.h>
#include <net/if_bridgevar.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#endif
#include "if_vrf.h"
MALLOC_DEFINE(M_VRF, "vrf", "Virtual Routing and Forwarding");
/* Maximum number of VRF interfaces */
#define VRF_MAXUNIT 0xFFFF /* Same as ifnet max */
/* Per-interface structure */
struct vrf_softc {
struct ifnet *vrf_ifp; /* Base interface */
u_int vrf_fibnum; /* FIB number */
uint32_t vrf_vni; /* VNI value */
struct rmlock vrf_mtx; /* For protecting members */
LIST_HEAD(, vrf_iflist) vrf_iflist; /* List of member interfaces */
eventhandler_tag vrf_detach_cookie;
};
/* Member interface structure */
struct vrf_iflist {
LIST_ENTRY(vrf_iflist) vrif_next; /* List of member interfaces */
struct ifnet *vrif_ifp; /* Member interface */
u_int32_t vrif_saved_fib; /* Original FIB before joining */
};
/* Interface cloner */
static struct if_clone *vrf_cloner;
static const char vrf_name[] = "vrf";
/* Forward declarations */
static int vrf_clone_create(struct if_clone *, int, caddr_t);
static void vrf_clone_destroy(struct ifnet *);
static int vrf_ioctl(struct ifnet *, u_long, caddr_t);
static int vrf_transmit(struct ifnet *, struct mbuf *);
static void vrf_qflush(struct ifnet *);
static int vrf_output(struct ifnet *, struct mbuf *,
const struct sockaddr *, struct route *);
static int vrf_attach_interface(struct vrf_softc *, struct ifnet *);
static int vrf_detach_interface(struct vrf_softc *, struct ifnet *);
static void vrf_interface_detached(void *, struct ifnet *);
static int vrf_add_interface(struct ifnet *, struct ifnet *);
static int vrf_remove_interface(struct ifnet *, struct ifnet *);
static void vrf_init(void *);
static int vrf_setfib(struct vrf_softc *, u_int);
static u_int vrf_get_fibnum(struct vrf_softc *);
static int vrf_setvni(struct vrf_softc *, uint32_t);
static uint32_t vrf_get_vni(struct vrf_softc *);
static struct vrf_iflist *vrf_find_iflist(struct vrf_softc *, struct ifnet *);
static int vrf_flush_interfaces(struct vrf_softc *, int);
static int vrf_cmd_handler(struct vrf_softc *, u_long, void *, size_t, int);
/* sysctl variables */
SYSCTL_DECL(_net_link);
SYSCTL_NODE(_net_link, IFT_VRF, vrf, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"Virtual Routing and Forwarding");
/*
* Driver initialization
*/
static void
vrf_init(void *dummy __unused)
{
/* Register if_clone */
vrf_cloner = if_clone_simple(vrf_name, vrf_clone_create, vrf_clone_destroy,
0);
}
SYSINIT(vrf_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vrf_init, NULL);
/*
* Create a VRF interface
*/
static int
vrf_clone_create(struct if_clone *ifc, int unit, caddr_t params)
{
struct vrf_softc *sc;
struct ifnet *ifp;
struct vrfparam *vrfp = (struct vrfparam *)params;
/* Allocate VRF softc */
sc = malloc(sizeof(struct vrf_softc), M_VRF, M_WAITOK | M_ZERO);
rm_init(&sc->vrf_mtx, "vrf_mtx");
LIST_INIT(&sc->vrf_iflist);
/* Default VNI is unset */
sc->vrf_vni = VRF_VNI_NONE;
/* Default FIB number is the same as the unit number, but caps at rt_numfibs */
sc->vrf_fibnum = min(unit, rt_numfibs - 1);
/* Process creation parameters if provided */
if (vrfp != NULL) {
if (vrfp->vrfp_with & VRF_PARAM_WITH_VNI &&
vrfp->vrfp_vni < VRF_VNI_MAX) {
sc->vrf_vni = vrfp->vrfp_vni;
}
if (vrfp->vrfp_with & VRF_PARAM_WITH_FIB &&
vrfp->vrfp_fib < rt_numfibs) {
sc->vrf_fibnum = vrfp->vrfp_fib;
}
}
/* Allocate ifnet structure */
ifp = if_alloc(IFT_VRF);
if (ifp == NULL) {
rm_destroy(&sc->vrf_mtx);
free(sc, M_VRF);
return (ENOSPC);
}
sc->vrf_ifp = ifp;
ifp->if_softc = sc;
/* Set ifnet fields */
if_initname(ifp, vrf_name, unit);
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
ifp->if_ioctl = vrf_ioctl;
ifp->if_transmit = vrf_transmit;
ifp->if_qflush = vrf_qflush;
ifp->if_output = vrf_output;
ifp->if_hdrlen = 0;
ifp->if_capabilities |= IFCAP_LINKSTATE;
ifp->if_capenable |= IFCAP_LINKSTATE;
/* Attach interface */
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
/* Register event handler for interface deletions */
sc->vrf_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
vrf_interface_detached, sc, EVENTHANDLER_PRI_ANY);
return (0);
}
/*
* Destroy a VRF interface
*/
static void
vrf_clone_destroy(struct ifnet *ifp)
{
struct vrf_softc *sc = ifp->if_softc;
struct vrf_iflist *vifl, *next;
/* Check if interface exists */
if (ifp == NULL || sc == NULL)
return;
/* Unregister event handler */
EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->vrf_detach_cookie);
/* Detach all member interfaces */
LIST_FOREACH_SAFE(vifl, &sc->vrf_iflist, vrif_next, next) {
vrf_detach_interface(sc, vifl->vrif_ifp);
}
/* Detach interface */
bpfdetach(ifp);
if_detach(ifp);
if_free(ifp);
/* Free softc */
rm_destroy(&sc->vrf_mtx);
free(sc, M_VRF);
}
/*
* Handle ioctl requests for VRF interfaces
*/
static int
vrf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct vrf_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct ifbreq *req = (struct ifbreq *)data;
struct ifdrv *ifd = (struct ifdrv *)data;
struct ifnet *ifs;
int error = 0;
switch (cmd) {
case SIOCADDMULTI:
case SIOCDELMULTI:
/* Nothing to do */
break;
case SIOCGVRFFIB:
/* Get VRF FIB number */
ifr->ifr_fib = vrf_get_fibnum(sc);
break;
case SIOCGVNETID:
/* Get FIB ID for application compatibility */
ifr->ifr_fib = vrf_get_vni(sc);
break;
case SIOCSVRFFIB:
/* Set VRF FIB number */
error = priv_check(curthread, PRIV_NET_SETIFFIB);
if (error)
break;
error = vrf_setfib(sc, ifr->ifr_fib);
break;
case SIOCSVNETID:
/* Set FIB ID for application compatibility */
error = priv_check(curthread, PRIV_NET_SETIFFIB);
if (error)
break;
error = vrf_setvni(sc, ifr->ifr_fib);
break;
case SIOCSDRVSPEC:
case SIOCGDRVSPEC:
/* Handle driver-specific ioctls */
error = priv_check(curthread, PRIV_NET_SETIFFIB);
if (error)
break;
if (ifd->ifd_cmd < VRF_CMD_GET_CONFIG ||
ifd->ifd_len < sizeof(struct vrfcmd)) {
error = EINVAL;
break;
}
error = vrf_cmd_handler(sc, ifd->ifd_cmd, ifd->ifd_data,
ifd->ifd_len, cmd == SIOCSDRVSPEC);
break;
case SIOCIFCREATE:
case SIOCIFDESTROY:
/* Let the cloner handle these */
return (EOPNOTSUPP);
case SIOCAIFGROUP:
case SIOCDIFGROUP:
/* Just pass these along to the underlying interfaces */
break;
case SIOCIFGMEMBERS:
/* Get list of member interfaces */
break;
case SIOCBRDGADD:
/* Add an interface to the VRF */
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
return (ENOENT);
error = vrf_add_interface(ifp, ifs);
break;
case SIOCBRDGDEL:
/* Remove an interface from the VRF */
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
return (ENOENT);
error = vrf_remove_interface(ifp, ifs);
break;
case SIOCSIFFLAGS:
/* Handle IFF_UP changes */
if (ifp->if_flags & IFF_UP)
ifp->if_drv_flags |= IFF_DRV_RUNNING;
else
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
break;
default:
error = ether_ioctl(ifp, cmd, data);
break;
}
return (error);
}
/*
* Handle VRF-specific commands
*/
static int
vrf_cmd_handler(struct vrf_softc *sc, u_long cmd, void *data, size_t datalen, int set)
{
struct vrfcmd *vrfcmd;
struct vrfcfg *vrfcfg;
struct vrf_iflist *vifl;
struct rm_priotracker tracker;
int error = 0;
/* Check parameter validity */
if (data == NULL || sc == NULL)
return (EINVAL);
switch (cmd) {
case VRF_CMD_GET_CONFIG:
if (!set && datalen >= sizeof(struct vrfcfg)) {
vrfcfg = (struct vrfcfg *)data;
vrfcfg->vrfc_vni = vrf_get_vni(sc);
vrfcfg->vrfc_fib = vrf_get_fibnum(sc);
/* Count member interfaces */
vrfcfg->vrfc_ifcnt = 0;
rm_rlock(&sc->vrf_mtx, &tracker);
LIST_FOREACH(vifl, &sc->vrf_iflist, vrif_next) {
vrfcfg->vrfc_ifcnt++;
}
rm_runlock(&sc->vrf_mtx, &tracker);
} else {
error = EINVAL;
}
break;
case VRF_CMD_SET_VNI:
if (set && datalen >= sizeof(struct vrfcmd)) {
vrfcmd = (struct vrfcmd *)data;
error = vrf_setvni(sc, vrfcmd->vrfcmd_vni);
} else {
error = EINVAL;
}
break;
case VRF_CMD_SET_FIB:
if (set && datalen >= sizeof(struct vrfcmd)) {
vrfcmd = (struct vrfcmd *)data;
error = vrf_setfib(sc, vrfcmd->vrfcmd_fib);
} else {
error = EINVAL;
}
break;
case VRF_CMD_FLUSH:
if (set && datalen >= sizeof(struct vrfcmd)) {
vrfcmd = (struct vrfcmd *)data;
error = vrf_flush_interfaces(sc,
(vrfcmd->vrfcmd_flags & VRF_CMD_FLAG_FLUSH_ALL) != 0);
} else {
error = EINVAL;
}
break;
default:
error = EINVAL;
break;
}
return (error);
}
/*
* Transmit function - we drop packets for a VRF itself
*/
static int
vrf_transmit(struct ifnet *ifp, struct mbuf *m)
{
/* VRF interfaces don't transmit packets directly */
m_freem(m);
return (0);
}
/*
* Flush output queue
*/
static void
vrf_qflush(struct ifnet *ifp)
{
/* Nothing to do, we don't buffer packets */
}
/*
* Output function - we drop packets for a VRF itself
*/
static int
vrf_output(struct ifnet *ifp, struct mbuf *m,
const struct sockaddr *dst, struct route *ro)
{
/* VRF interfaces don't transmit packets directly */
m_freem(m);
return (ENETDOWN);
}
/*
* Add a member interface to the VRF
*/
static int
vrf_add_interface(struct ifnet *vrf_ifp, struct ifnet *ifs)
{
struct vrf_softc *sc = vrf_ifp->if_softc;
int error;
/* Don't allow adding a VRF to itself or another VRF */
if (ifs->if_type == IFT_VRF)
return (EINVAL);
/* Add interface to VRF */
error = vrf_attach_interface(sc, ifs);
return (error);
}
/*
* Remove a member interface from the VRF
*/
static int
vrf_remove_interface(struct ifnet *vrf_ifp, struct ifnet *ifs)
{
struct vrf_softc *sc = vrf_ifp->if_softc;
int error;
/* Remove interface from VRF */
error = vrf_detach_interface(sc, ifs);
return (error);
}
/*
* Attach a member interface to a VRF
*/
static int
vrf_attach_interface(struct vrf_softc *sc, struct ifnet *ifs)
{
struct vrf_iflist *vifl;
/* Check if already a member */
rm_wlock(&sc->vrf_mtx);
if (vrf_find_iflist(sc, ifs) != NULL) {
rm_wunlock(&sc->vrf_mtx);
return (EEXIST);
}
/* Allocate and add new member */
vifl = malloc(sizeof(struct vrf_iflist), M_VRF, M_NOWAIT | M_ZERO);
if (vifl == NULL) {
rm_wunlock(&sc->vrf_mtx);
return (ENOMEM);
}
vifl->vrif_ifp = ifs;
vifl->vrif_saved_fib = ifs->if_fib;
/* Set interface FIB to VRF FIB */
ifs->if_fib = sc->vrf_fibnum;
/* Add to list */
LIST_INSERT_HEAD(&sc->vrf_iflist, vifl, vrif_next);
rm_wunlock(&sc->vrf_mtx);
printf("VRF %s: Added interface %s (FIB %u)\n",
sc->vrf_ifp->if_xname, ifs->if_xname, sc->vrf_fibnum);
return (0);
}
/*
* Detach a member interface from a VRF
*/
static int
vrf_detach_interface(struct vrf_softc *sc, struct ifnet *ifs)
{
struct vrf_iflist *vifl;
/* Find and remove member */
rm_wlock(&sc->vrf_mtx);
vifl = vrf_find_iflist(sc, ifs);
if (vifl == NULL) {
rm_wunlock(&sc->vrf_mtx);
return (ENOENT);
}
/* Restore original FIB */
ifs->if_fib = vifl->vrif_saved_fib;
/* Remove from list */
LIST_REMOVE(vifl, vrif_next);
rm_wunlock(&sc->vrf_mtx);
printf("VRF %s: Removed interface %s (restored FIB %u)\n",
sc->vrf_ifp->if_xname, ifs->if_xname, vifl->vrif_saved_fib);
free(vifl, M_VRF);
return (0);
}
/*
* Remove all interfaces from the VRF
*/
static int
vrf_flush_interfaces(struct vrf_softc *sc, int all)
{
struct vrf_iflist *vifl, *next;
int count = 0;
rm_wlock(&sc->vrf_mtx);
LIST_FOREACH_SAFE(vifl, &sc->vrf_iflist, vrif_next, next) {
/* Restore original FIB */
vifl->vrif_ifp->if_fib = vifl->vrif_saved_fib;
/* Remove from list */
LIST_REMOVE(vifl, vrif_next);
printf("VRF %s: Flushed interface %s (restored FIB %u)\n",
sc->vrf_ifp->if_xname, vifl->vrif_ifp->if_xname,
vifl->vrif_saved_fib);
free(vifl, M_VRF);
count++;
/* If not flushing all, just remove one interface */
if (!all)
break;
}
rm_wunlock(&sc->vrf_mtx);
return (count > 0 ? 0 : ENOENT);
}
/*
* Handle interface detach events
*/
static void
vrf_interface_detached(void *arg, struct ifnet *ifs)
{
struct vrf_softc *sc = arg;
struct vrf_iflist *vifl;
struct rm_priotracker tracker;
/* Check if the detached interface is a member of our VRF */
rm_rlock(&sc->vrf_mtx, &tracker);
vifl = vrf_find_iflist(sc, ifs);
if (vifl != NULL) {
rm_runlock(&sc->vrf_mtx, &tracker);
vrf_detach_interface(sc, ifs);
} else {
rm_runlock(&sc->vrf_mtx, &tracker);
}
}
/*
* Set the FIB number for a VRF
*/
static int
vrf_setfib(struct vrf_softc *sc, u_int fibnum)
{
struct vrf_iflist *vifl;
struct rm_priotracker tracker;
u_int oldfib;
/* Check if FIB is valid */
if (fibnum >= rt_numfibs)
return (EINVAL);
/* Check if FIB is changing */
if (sc->vrf_fibnum == fibnum)
return (0);
oldfib = sc->vrf_fibnum;
/* Update all member interfaces */
rm_rlock(&sc->vrf_mtx, &tracker);
sc->vrf_fibnum = fibnum;
LIST_FOREACH(vifl, &sc->vrf_iflist, vrif_next) {
vifl->vrif_ifp->if_fib = fibnum;
}
rm_runlock(&sc->vrf_mtx, &tracker);
printf("VRF %s: FIB changed from %u to %u\n",
sc->vrf_ifp->if_xname, oldfib, fibnum);
return (0);
}
/*
* Get the FIB number for a VRF
*/
static u_int
vrf_get_fibnum(struct vrf_softc *sc)
{
return (sc->vrf_fibnum);
}
/*
* Set the VNI for a VRF
*/
static int
vrf_setvni(struct vrf_softc *sc, uint32_t vni)
{
uint32_t oldvni;
/* Check if VNI is valid */
if (vni >= VRF_VNI_MAX)
return (EINVAL);
/* Check if VNI is changing */
if (sc->vrf_vni == vni)
return (0);
oldvni = sc->vrf_vni;
sc->vrf_vni = vni;
printf("VRF %s: VNI changed from %u to %u\n",
sc->vrf_ifp->if_xname, oldvni, vni);
return (0);
}
/*
* Get the VNI for a VRF
*/
static uint32_t
vrf_get_vni(struct vrf_softc *sc)
{
return (sc->vrf_vni);
}
/*
* Find a member interface in a VRF
*/
static struct vrf_iflist *
vrf_find_iflist(struct vrf_softc *sc, struct ifnet *ifs)
{
struct vrf_iflist *vifl;
LIST_FOREACH(vifl, &sc->vrf_iflist, vrif_next) {
if (vifl->vrif_ifp == ifs)
return (vifl);
}
return (NULL);
}
/*
* Module event handler
*/
static int
vrf_modevent(module_t mod, int type, void *data)
{
int error = 0;
switch (type) {
case MOD_LOAD:
/* Module initialization is handled by SYSINIT */
printf("VRF: Virtual Routing and Forwarding interface loaded\n");
break;
case MOD_UNLOAD:
/* Check if any instances exist */
if (vrf_cloner != NULL) {
if_clone_detach(vrf_cloner);
printf("VRF: Virtual Routing and Forwarding interface unloaded\n");
}
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
/* Module declaration */
static moduledata_t vrf_mod = {
"if_vrf",
vrf_modevent,
0
};
DECLARE_MODULE(if_vrf, vrf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_VERSION(if_vrf, 1);
/*
* Copyright (c) 2023 Your Name
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _NET_IF_VRF_H_
#define _NET_IF_VRF_H_
#include <netinet/in.h>
#include <sys/ioccom.h>
/* Define a unique interface type for VRF */
#define IFT_VRF 0xFA /* Virtual Routing and Forwarding */
/* VRF-specific ioctls */
#define SIOCGVRFFIB _IOR('i', 150, struct ifreq) /* get VRF FIB */
#define SIOCSVRFFIB _IOW('i', 151, struct ifreq) /* set VRF FIB */
#define SIOCGVNETID _IOR('i', 152, struct ifreq) /* get VRF VNI */
#define SIOCSVNETID _IOW('i', 153, struct ifreq) /* set VRF VNI */
#define SIOCIFGMEMBERS _IOWR('i', 154, struct ifdrv) /* get VRF members */
#define SIOCBRDGADD _IOW('i', 155, struct ifbreq) /* add interface */
#define SIOCBRDGDEL _IOW('i', 156, struct ifbreq) /* remove interface */
/* Maximum VNI value (24 bits, matching VXLAN) */
#define VRF_VNI_MAX ((1 << 24) - 1)
#define VRF_VNI_NONE VRF_VNI_MAX /* Unset VNI value */
/* VRF specific ioctl commands */
#define VRF_CMD_GET_CONFIG 1
#define VRF_CMD_SET_VNI 2
#define VRF_CMD_SET_FIB 3
#define VRF_CMD_FLUSH 4
/* Structure to pass VRF commands via ioctl */
struct vrfcmd {
uint32_t vrfcmd_vni; /* VNI */
uint32_t vrfcmd_fib; /* FIB number */
uint32_t vrfcmd_flags; /* Command flags */
#define VRF_CMD_FLAG_FLUSH_ALL 0x00000001 /* Flush all interfaces */
};
/* VRF configuration data */
struct vrfcfg {
uint32_t vrfc_vni; /* VNI */
uint32_t vrfc_fib; /* FIB number */
uint32_t vrfc_ifcnt; /* Number of member interfaces */
};
/* Structure to set up a VRF interface */
struct vrfparam {
uint32_t vrfp_vni; /* VNI */
uint32_t vrfp_fib; /* FIB number */
uint32_t vrfp_with; /* Flags indicating which params are valid */
#define VRF_PARAM_WITH_VNI 0x00000001
#define VRF_PARAM_WITH_FIB 0x00000002
};
#ifdef _KERNEL
/* Function prototypes for kernel components */
void rt_set_ifscope(struct ifnet *ifp, u_int fibnum);
#else /* !_KERNEL */
/* These are only used from userland */
#endif /* _KERNEL */
#endif /* _NET_IF_VRF_H_ */
#define SMP 1
#define MAC 1
#define VIMAGE 1
#define EARLY_AP_STARTUP 1
#define CC_CUBIC 1
#define NEW_PCIB 1
#define NETLINK 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment