Index: sbin/dhclient/bpf.c =================================================================== --- sbin/dhclient/bpf.c +++ sbin/dhclient/bpf.c @@ -90,6 +90,14 @@ error("Can't attach interface %s to bpf device %s: %m", info->name, filename); + /* Tag the packets with the proper VLAN PCP setting. */ + if (info->client->config->vlan_pcp != 0) { + if (ioctl(sock, BIOCSETPCP, + &info->client->config->vlan_pcp) < 0) + error( "Can't set the VLAN PCP tag on interface %s: %m", + info->name); + } + return (sock); } Index: sbin/dhclient/clparse.c =================================================================== --- sbin/dhclient/clparse.c +++ sbin/dhclient/clparse.c @@ -76,6 +76,7 @@ memset(&top_level_config, 0, sizeof(top_level_config)); /* Set some defaults... */ + top_level_config.vlan_pcp = 0; top_level_config.timeout = 60; top_level_config.select_interval = 0; top_level_config.reboot_timeout = 10; @@ -201,6 +202,7 @@ int token; char *val; struct option *option; + time_t tmp; switch (next_token(&val, cfile)) { case SEND: @@ -260,6 +262,10 @@ case REBOOT: parse_lease_time(cfile, &config->reboot_timeout); return; + case VLAN_PCP: + parse_lease_time(cfile, &tmp); + config->vlan_pcp = (u_int)tmp; + return; case BACKOFF_CUTOFF: parse_lease_time(cfile, &config->backoff_cutoff); return; Index: sbin/dhclient/conflex.c =================================================================== --- sbin/dhclient/conflex.c +++ sbin/dhclient/conflex.c @@ -524,6 +524,8 @@ case 'v': if (!strcasecmp(atom + 1, "endor-class")) return (VENDOR_CLASS); + if (!strcasecmp(atom + 1, "lan-pcp")) + return (VLAN_PCP); break; case 'y': if (!strcasecmp(atom + 1, "iaddr")) Index: sbin/dhclient/dhclient.conf.5 =================================================================== --- sbin/dhclient/dhclient.conf.5 +++ sbin/dhclient/dhclient.conf.5 @@ -38,7 +38,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 31, 2018 +.Dd July 21, 2021 .Dt DHCLIENT.CONF 5 .Os .Sh NAME @@ -484,6 +484,13 @@ Whenever the client tries to renew the lease, it will use that same media type. The lease must expire before the client will go back to cycling through media types. +.It Ic vlan-pcp Ar code ; +The +.Ic vlan-pcp +statement sets the PCP (Priority Code Point) value for the VLAN header. +This requires the +.Va net.link.vlan.mtag_pcp +sysctl to be set to 1. .El .Sh EXAMPLES The following configuration file is used on a laptop Index: sbin/dhclient/dhcpd.h =================================================================== --- sbin/dhclient/dhcpd.h +++ sbin/dhclient/dhcpd.h @@ -159,6 +159,7 @@ u_int8_t required_options[256]; u_int8_t requested_options[256]; int requested_option_count; + u_int vlan_pcp; time_t timeout; time_t initial_interval; time_t retry_interval; Index: sbin/dhclient/dhctoken.h =================================================================== --- sbin/dhclient/dhctoken.h +++ sbin/dhclient/dhctoken.h @@ -133,6 +133,7 @@ #define AUTHORITATIVE 333 #define TOKEN_NOT 334 #define ALWAYS_REPLY_RFC1048 335 +#define VLAN_PCP 336 #define is_identifier(x) ((x) >= FIRST_TOKEN && \ (x) != STRING && \ Index: sys/net/bpf.h =================================================================== --- sys/net/bpf.h +++ sys/net/bpf.h @@ -153,6 +153,7 @@ #define BIOCSETFNR _IOW('B', 130, struct bpf_program) #define BIOCGTSTAMP _IOR('B', 131, u_int) #define BIOCSTSTAMP _IOW('B', 132, u_int) +#define BIOCSETPCP _IOW('B', 133, u_int) /* Obsolete */ #define BIOCGSEESENT BIOCGDIRECTION Index: sys/net/bpf.c =================================================================== --- sys/net/bpf.c +++ sys/net/bpf.c @@ -78,6 +78,7 @@ #include #include +#include #include #include #include @@ -130,6 +131,7 @@ #if defined(DEV_BPF) || defined(NETGRAPH_BPF) #define PRINET 26 /* interruptible */ +#define BPF_PRIO_MAX 7 #define SIZEOF_BPF_HDR(type) \ (offsetof(type, bh_hdrlen) + sizeof(((type *)0)->bh_hdrlen)) @@ -977,6 +979,9 @@ callout_init_mtx(&d->bd_callout, &d->bd_lock, 0); knlist_init_mtx(&d->bd_sel.si_note, &d->bd_lock); + /* Disable VLAN pcp tagging. */ + d->bd_pcp = 0; + return (0); } @@ -1167,6 +1172,27 @@ return (0); } +static int +bpf_setpcp(struct mbuf *m, u_int8_t prio) +{ + struct m_tag *mtag; + + KASSERT(prio <= BPF_PRIO_MAX, + ("%s with invalid pcp", __func__)); + + mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_OUT, NULL); + if (mtag == NULL) { + mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_OUT, + sizeof(uint8_t), M_NOWAIT); + if (mtag == NULL) + return (ENOMEM); + m_tag_prepend(m, mtag); + } + + *(uint8_t *)(mtag + 1) = prio; + return (0); +} + static int bpfwrite(struct cdev *dev, struct uio *uio, int ioflag) { @@ -1267,6 +1293,9 @@ ro.ro_flags = RT_HAS_HEADER; } + if (d->bd_pcp != 0) + bpf_setpcp(m, d->bd_pcp); + /* Avoid possible recursion on BPFD_LOCK(). */ NET_EPOCH_ENTER(et); BPFD_UNLOCK(d); @@ -1356,6 +1385,7 @@ * BIOCROTZBUF Force rotation of zero-copy buffer * BIOCSETBUFMODE Set buffer mode. * BIOCGETBUFMODE Get current buffer mode. + * BIOCSETPCP Set VLAN PCP tag. */ /* ARGSUSED */ static int @@ -1906,6 +1936,19 @@ case BIOCROTZBUF: error = bpf_ioctl_rotzbuf(td, d, (struct bpf_zbuf *)addr); break; + + case BIOCSETPCP: + { + u_int pcp; + + pcp = *(u_int *)addr; + if (pcp > BPF_PRIO_MAX || pcp < 0) { + error = EINVAL; + break; + } + d->bd_pcp = pcp; + break; + } } CURVNET_RESTORE(); return (error); Index: sys/net/bpfdesc.h =================================================================== --- sys/net/bpfdesc.h +++ sys/net/bpfdesc.h @@ -91,6 +91,7 @@ int bd_feedback; /* true to feed back sent packets */ int bd_async; /* non-zero if packet reception should generate signal */ int bd_sig; /* signal to send upon packet reception */ + int bd_pcp; /* VLAN pcp tag */ struct sigio * bd_sigio; /* information for async I/O */ struct selinfo bd_sel; /* bsd select info */ struct mtx bd_lock; /* per-descriptor lock */