diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h --- a/lib/libifconfig/libifconfig.h +++ b/lib/libifconfig/libifconfig.h @@ -69,6 +69,8 @@ size_t members_count; /**< how many member interfaces */ uint32_t cache_size; /**< size of address cache */ uint32_t cache_lifetime; /**< address cache entry lifetime */ + ifbr_flags_t flags; /**< bridge flags */ + ether_vlanid_t defpvid; /**< default pvid */ }; struct ifconfig_capabilities { diff --git a/lib/libifconfig/libifconfig_bridge.c b/lib/libifconfig/libifconfig_bridge.c --- a/lib/libifconfig/libifconfig_bridge.c +++ b/lib/libifconfig/libifconfig_bridge.c @@ -92,6 +92,18 @@ } bridge->inner.cache_lifetime = cache_param.ifbrp_ctime; + if (ifconfig_bridge_ioctlwrap(h, name, BRDGGFLAGS, + &cache_param, sizeof(cache_param), false) != 0) { + goto err; + } + bridge->inner.flags = cache_param.ifbrp_flags; + + if (ifconfig_bridge_ioctlwrap(h, name, BRDGGDEFPVID, + &cache_param, sizeof(cache_param), false) != 0) { + goto err; + } + bridge->inner.defpvid = cache_param.ifbrp_defpvid; + if (ifconfig_bridge_ioctlwrap(h, name, BRDGPARAM, &bridge->params, sizeof(bridge->params), false) != 0) { goto err; diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c --- a/sbin/ifconfig/ifbridge.c +++ b/sbin/ifconfig/ifbridge.c @@ -209,6 +209,11 @@ params->ifbop_root_path_cost, params->ifbop_root_port & 0xfff); + printb("\tbridge flags", bridge->flags, IFBRFBITS); + if (bridge->defpvid) + printf(" defuntagged=%u", (unsigned) bridge->defpvid); + printf("\n"); + prefix = "\tmember: "; pad = "\t "; for (size_t i = 0; i < bridge->members_count; ++i) { @@ -462,7 +467,6 @@ static void setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused) { - bridge_addresses(ctx, ""); } @@ -796,6 +800,63 @@ set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL); } +static void +setbridge_flags(if_ctx *ctx, const char *val __unused, int newflags) +{ + struct ifbrparam req; + + if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0) + err(1, "BRDGGFLAGS"); + + req.ifbrp_flags |= (uint32_t)newflags; + + if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0) + err(1, "BRDGSFLAGS"); +} + +static void +unsetbridge_flags(if_ctx *ctx, const char *val __unused, int newflags) +{ + struct ifbrparam req; + + if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0) + err(1, "BRDGGFLAGS"); + + req.ifbrp_flags &= ~(uint32_t)newflags; + + if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0) + err(1, "BRDGSFLAGS"); +} + +static void +setbridge_defuntagged(if_ctx *ctx, const char *arg, int dummy __unused) +{ + struct ifbrparam req; + u_long vid; + + if (get_val(arg, &vid) < 0 || vid < DOT1Q_VID_MIN || + vid > DOT1Q_VID_MAX) + errx(1, "invalid value: %s", arg); + + memset(&req, 0, sizeof(req)); + req.ifbrp_defpvid = (ether_vlanid_t)vid; + + if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0) + err(1, "BRDGSDEFPVID"); +} + +static void +unsetbridge_defuntagged(if_ctx *ctx, const char *val __unused, int dummy __unused) +{ + struct ifbrparam req; + + memset(&req, 0, sizeof(req)); + req.ifbrp_defpvid = 0; + + if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0) + err(1, "BRDGSDEFPVID"); +} + static struct cmd bridge_cmds[] = { DEF_CMD_ARG("addm", setbridge_add), DEF_CMD_ARG("deletem", setbridge_delete), @@ -842,7 +903,14 @@ DEF_CMD_ARG("timeout", setbridge_timeout), DEF_CMD_ARG("private", setbridge_private), DEF_CMD_ARG("-private", unsetbridge_private), + DEF_CMD("defvlanfilter", (int32_t)IFBRF_DEFVLANFILTER, + setbridge_flags), + DEF_CMD("-defvlanfilter", (int32_t)IFBRF_DEFVLANFILTER, + unsetbridge_flags), + DEF_CMD_ARG("defuntagged", setbridge_defuntagged), + DEF_CMD("-defuntagged", 0, unsetbridge_defuntagged), }; + static struct afswtch af_bridge = { .af_name = "af_bridge", .af_af = AF_UNSPEC, diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 5, 2025 +.Dd July 6, 2025 .Dt IFCONFIG 8 .Os .Sh NAME @@ -2706,6 +2706,14 @@ Enable VLAN filtering on an interface. .It Cm -vlanfilter Ar interface Disable VLAN filtering on an interface. +.It Cm defvlanfilter +Enable the +.Cm vlanfilter +option by default on newly added members. +.It Cm -defvlanfilter +Do not enable the +.Cm vlanfilter +option by default on newly added members. .It Cm untagged Ar interface Ar vlan-id Set the untagged VLAN identifier for an interface. .Pp @@ -2714,6 +2722,14 @@ will automatically enable VLAN filtering on the interface. .It Cm -untagged Ar interface Ar vlan-id Clear the untagged VLAN identifier for an interface. +.It Cm defuntagged Ar vlan-id +Enable the +.Cm untagged +option by default on newly added members. +.It Cm -defuntagged +Do not enable the +.Cm untagged +option by default on newly added members. .It Cm tagged Ar interface Ar vlan-list Set the interface's VLAN access list to the provided list of VLANs. The list should be a comma-separated list of one or more VLAN IDs diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -297,6 +297,8 @@ struct ether_addr sc_defaddr; /* Default MAC address */ if_input_fn_t sc_if_input; /* Saved copy of if_input */ struct epoch_context sc_epoch_ctx; + ifbr_flags_t sc_flags; /* bridge flags */ + ether_vlanid_t sc_defpvid; /* default PVID */ }; VNET_DEFINE_STATIC(struct sx, bridge_list_sx); @@ -414,6 +416,10 @@ static int bridge_ioctl_gifsstp(struct bridge_softc *, void *); static int bridge_ioctl_sproto(struct bridge_softc *, void *); static int bridge_ioctl_stxhc(struct bridge_softc *, void *); +static int bridge_ioctl_gflags(struct bridge_softc *, void *); +static int bridge_ioctl_sflags(struct bridge_softc *, void *); +static int bridge_ioctl_gdefpvid(struct bridge_softc *, void *); +static int bridge_ioctl_sdefpvid(struct bridge_softc *, void *); static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, int); #ifdef INET @@ -633,6 +639,18 @@ { bridge_ioctl_gifvlanset, sizeof(struct ifbif_vlan_req), BC_F_COPYIN|BC_F_COPYOUT }, + + { bridge_ioctl_gflags, sizeof(struct ifbrparam), + BC_F_COPYOUT }, + + { bridge_ioctl_sflags, sizeof(struct ifbrparam), + BC_F_COPYIN|BC_F_SUSER }, + + { bridge_ioctl_gdefpvid, sizeof(struct ifbrparam), + BC_F_COPYOUT }, + + { bridge_ioctl_sdefpvid, sizeof(struct ifbrparam), + BC_F_COPYIN|BC_F_SUSER }, }; static const int bridge_control_table_size = nitems(bridge_control_table); @@ -1432,6 +1450,10 @@ bif->bif_ifp = ifs; bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; bif->bif_savedcaps = ifs->if_capenable; + if (sc->sc_flags & IFBRF_DEFVLANFILTER) { + bif->bif_flags |= IFBIF_VLANFILTER; + bif->bif_untagged = sc->sc_defpvid; + } /* * Assign the interface's MAC address to the bridge if it's the first @@ -2142,6 +2164,50 @@ return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc)); } +static int +bridge_ioctl_gflags(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + param->ifbrp_flags = sc->sc_flags; + + return (0); +} + +static int +bridge_ioctl_sflags(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + sc->sc_flags = param->ifbrp_flags; + + return (0); +} + +static int +bridge_ioctl_gdefpvid(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + param->ifbrp_defpvid = sc->sc_defpvid; + + return (0); +} + +static int +bridge_ioctl_sdefpvid(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + /* Reject invalid VIDs, but allow 0 to mean 'none'. */ + if (param->ifbrp_defpvid > DOT1Q_VID_MAX) + return (EINVAL); + + sc->sc_defpvid = param->ifbrp_defpvid; + + return (0); +} + /* * bridge_ifdetach: * diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -127,6 +127,17 @@ #define BRDGSIFUNTAGGED 31 /* set if untagged vlan */ #define BRDGSIFVLANSET 32 /* set if vlan set */ #define BRDGGIFVLANSET 33 /* get if vlan set */ +#define BRDGGFLAGS 34 /* get bridge flags (ifbrparam) */ +#define BRDGSFLAGS 35 /* set bridge flags (ifbrparam) */ +#define BRDGGDEFPVID 36 /* get default pvid (ifbrparam) */ +#define BRDGSDEFPVID 37 /* set default pvid (ifbrparam) */ + +/* BRDGSFLAGS, Bridge flags (non-interface-specific) */ +typedef uint32_t ifbr_flags_t; + +#define IFBRF_DEFVLANFILTER (1U<<0) /* enable vlanfilter by default */ + +#define IFBRFBITS "\020\01DEFVLANFILTER" /* * Generic bridge control request. @@ -237,7 +248,10 @@ #define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_int8 /* fwd time (sec) */ #define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_int8 /* max age (sec) */ #define ifbrp_cexceeded ifbrp_ifbrpu.ifbrpu_int32 /* # of cache dropped - * adresses */ + * addresses */ +#define ifbrp_flags ifbrp_ifbrpu.ifbrpu_int32 /* bridge flags */ +#define ifbrp_defpvid ifbrp_ifbrpu.ifbrpu_int16 /* default pvid */ + /* * Bridge current operational parameters structure. */