Skip to content

Commit 9807019

Browse files
kot-begemot-ukrichardweinberger
authored andcommitted
um: Loadable BPF "Firmware" for vector drivers
All vector drivers now allow a BPF program to be loaded and associated with the RX socket in the host kernel. 1. The program can be loaded as an extra kernel command line option to any of the vector drivers. 2. The program can also be loaded as "firmware", using the ethtool flash option. It is possible to turn this facility on or off using a command line option. A simplistic wrapper for generating the BPF firmware for the raw socket driver out of a tcpdump/libpcap filter expression can be found at: https://github.com/kot-begemot-uk/uml_vector_utilities/ Signed-off-by: Anton Ivanov <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 7d8093a commit 9807019

File tree

4 files changed

+193
-30
lines changed

4 files changed

+193
-30
lines changed

arch/um/drivers/vector_kern.c

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* Copyright (C) 2017 - Cambridge Greys Limited
3+
* Copyright (C) 2017 - 2019 Cambridge Greys Limited
44
* Copyright (C) 2011 - 2014 Cisco Systems Inc
55
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
66
* Copyright (C) 2001 Lennert Buytenhek ([email protected]) and
@@ -21,6 +21,9 @@
2121
#include <linux/skbuff.h>
2222
#include <linux/slab.h>
2323
#include <linux/interrupt.h>
24+
#include <linux/firmware.h>
25+
#include <linux/fs.h>
26+
#include <uapi/linux/filter.h>
2427
#include <init.h>
2528
#include <irq_kern.h>
2629
#include <irq_user.h>
@@ -128,6 +131,23 @@ static int get_mtu(struct arglist *def)
128131
return ETH_MAX_PACKET;
129132
}
130133

134+
static char *get_bpf_file(struct arglist *def)
135+
{
136+
return uml_vector_fetch_arg(def, "bpffile");
137+
}
138+
139+
static bool get_bpf_flash(struct arglist *def)
140+
{
141+
char *allow = uml_vector_fetch_arg(def, "bpfflash");
142+
long result;
143+
144+
if (allow != NULL) {
145+
if (kstrtoul(allow, 10, &result) == 0)
146+
return (allow > 0);
147+
}
148+
return false;
149+
}
150+
131151
static int get_depth(struct arglist *def)
132152
{
133153
char *mtu = uml_vector_fetch_arg(def, "depth");
@@ -176,6 +196,7 @@ static int get_transport_options(struct arglist *def)
176196
int vec_rx = VECTOR_RX;
177197
int vec_tx = VECTOR_TX;
178198
long parsed;
199+
int result = 0;
179200

180201
if (vector != NULL) {
181202
if (kstrtoul(vector, 10, &parsed) == 0) {
@@ -186,14 +207,16 @@ static int get_transport_options(struct arglist *def)
186207
}
187208
}
188209

210+
if (get_bpf_flash(def))
211+
result = VECTOR_BPF_FLASH;
189212

190213
if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
191-
return 0;
214+
return result;
192215
if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
193-
return (vec_rx | VECTOR_BPF);
216+
return (result | vec_rx | VECTOR_BPF);
194217
if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
195-
return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS);
196-
return (vec_rx | vec_tx);
218+
return (result | vec_rx | vec_tx | VECTOR_QDISC_BYPASS);
219+
return (result | vec_rx | vec_tx);
197220
}
198221

199222

@@ -1139,14 +1162,19 @@ static int vector_net_close(struct net_device *dev)
11391162
}
11401163
tasklet_kill(&vp->tx_poll);
11411164
if (vp->fds->rx_fd > 0) {
1165+
if (vp->bpf)
1166+
uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf);
11421167
os_close_file(vp->fds->rx_fd);
11431168
vp->fds->rx_fd = -1;
11441169
}
11451170
if (vp->fds->tx_fd > 0) {
11461171
os_close_file(vp->fds->tx_fd);
11471172
vp->fds->tx_fd = -1;
11481173
}
1174+
if (vp->bpf != NULL)
1175+
kfree(vp->bpf->filter);
11491176
kfree(vp->bpf);
1177+
vp->bpf = NULL;
11501178
kfree(vp->fds->remote_addr);
11511179
kfree(vp->transport_data);
11521180
kfree(vp->header_rxbuffer);
@@ -1181,6 +1209,7 @@ static void vector_reset_tx(struct work_struct *work)
11811209
netif_start_queue(vp->dev);
11821210
netif_wake_queue(vp->dev);
11831211
}
1212+
11841213
static int vector_net_open(struct net_device *dev)
11851214
{
11861215
struct vector_private *vp = netdev_priv(dev);
@@ -1196,6 +1225,8 @@ static int vector_net_open(struct net_device *dev)
11961225
vp->opened = true;
11971226
spin_unlock_irqrestore(&vp->lock, flags);
11981227

1228+
vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed));
1229+
11991230
vp->fds = uml_vector_user_open(vp->unit, vp->parsed);
12001231

12011232
if (vp->fds == NULL)
@@ -1267,8 +1298,11 @@ static int vector_net_open(struct net_device *dev)
12671298
if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd))
12681299
vp->options |= VECTOR_BPF;
12691300
}
1270-
if ((vp->options & VECTOR_BPF) != 0)
1271-
vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr);
1301+
if (((vp->options & VECTOR_BPF) != 0) && (vp->bpf == NULL))
1302+
vp->bpf = uml_vector_default_bpf(dev->dev_addr);
1303+
1304+
if (vp->bpf != NULL)
1305+
uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf);
12721306

12731307
netif_start_queue(dev);
12741308

@@ -1347,6 +1381,65 @@ static void vector_net_get_drvinfo(struct net_device *dev,
13471381
strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
13481382
}
13491383

1384+
static int vector_net_load_bpf_flash(struct net_device *dev,
1385+
struct ethtool_flash *efl)
1386+
{
1387+
struct vector_private *vp = netdev_priv(dev);
1388+
struct vector_device *vdevice;
1389+
const struct firmware *fw;
1390+
int result = 0;
1391+
1392+
if (!(vp->options & VECTOR_BPF_FLASH)) {
1393+
netdev_err(dev, "loading firmware not permitted: %s\n", efl->data);
1394+
return -1;
1395+
}
1396+
1397+
spin_lock(&vp->lock);
1398+
1399+
if (vp->bpf != NULL) {
1400+
if (vp->opened)
1401+
uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf);
1402+
kfree(vp->bpf->filter);
1403+
vp->bpf->filter = NULL;
1404+
} else {
1405+
vp->bpf = kmalloc(sizeof(struct sock_fprog), GFP_KERNEL);
1406+
if (vp->bpf == NULL) {
1407+
netdev_err(dev, "failed to allocate memory for firmware\n");
1408+
goto flash_fail;
1409+
}
1410+
}
1411+
1412+
vdevice = find_device(vp->unit);
1413+
1414+
if (request_firmware(&fw, efl->data, &vdevice->pdev.dev))
1415+
goto flash_fail;
1416+
1417+
vp->bpf->filter = kmemdup(fw->data, fw->size, GFP_KERNEL);
1418+
if (!vp->bpf->filter)
1419+
goto free_buffer;
1420+
1421+
vp->bpf->len = fw->size / sizeof(struct sock_filter);
1422+
release_firmware(fw);
1423+
1424+
if (vp->opened)
1425+
result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf);
1426+
1427+
spin_unlock(&vp->lock);
1428+
1429+
return result;
1430+
1431+
free_buffer:
1432+
release_firmware(fw);
1433+
1434+
flash_fail:
1435+
spin_unlock(&vp->lock);
1436+
if (vp->bpf != NULL)
1437+
kfree(vp->bpf->filter);
1438+
kfree(vp->bpf);
1439+
vp->bpf = NULL;
1440+
return -1;
1441+
}
1442+
13501443
static void vector_get_ringparam(struct net_device *netdev,
13511444
struct ethtool_ringparam *ring)
13521445
{
@@ -1424,6 +1517,7 @@ static const struct ethtool_ops vector_net_ethtool_ops = {
14241517
.get_ethtool_stats = vector_get_ethtool_stats,
14251518
.get_coalesce = vector_get_coalesce,
14261519
.set_coalesce = vector_set_coalesce,
1520+
.flash_device = vector_net_load_bpf_flash,
14271521
};
14281522

14291523

@@ -1528,8 +1622,9 @@ static void vector_eth_configure(
15281622
.in_write_poll = false,
15291623
.coalesce = 2,
15301624
.req_size = get_req_size(def),
1531-
.in_error = false
1532-
});
1625+
.in_error = false,
1626+
.bpf = NULL
1627+
});
15331628

15341629
dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST);
15351630
tasklet_init(&vp->tx_poll, vector_tx_poll, (unsigned long)vp);

arch/um/drivers/vector_kern.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@
2929
#define VECTOR_TX (1 << 1)
3030
#define VECTOR_BPF (1 << 2)
3131
#define VECTOR_QDISC_BYPASS (1 << 3)
32+
#define VECTOR_BPF_FLASH (1 << 4)
3233

3334
#define ETH_MAX_PACKET 1500
3435
#define ETH_HEADER_OTHER 32 /* just in case someone decides to go mad on QnQ */
3536

37+
#define MAX_FILTER_PROG (2 << 16)
38+
3639
struct vector_queue {
3740
struct mmsghdr *mmsg_vector;
3841
void **skbuff_vector;
@@ -118,10 +121,13 @@ struct vector_private {
118121
bool in_write_poll;
119122
bool in_error;
120123

124+
/* guest allowed to use ethtool flash to load bpf */
125+
bool bpf_via_flash;
126+
121127
/* ethtool stats */
122128

123129
struct vector_estats estats;
124-
void *bpf;
130+
struct sock_fprog *bpf;
125131

126132
char user[0];
127133
};

arch/um/drivers/vector_user.c

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
#define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
4747
#define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
4848
#define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i"
49-
#define BPF_ATTACH_FAIL "Failed to attach filter size %d to %d, err %d\n"
49+
#define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n"
50+
#define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n"
5051

5152
#define MAX_UN_LEN 107
5253

@@ -660,31 +661,44 @@ int uml_vector_recvmmsg(
660661
else
661662
return -errno;
662663
}
663-
int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len)
664+
int uml_vector_attach_bpf(int fd, void *bpf)
664665
{
665-
int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, bpf_len);
666+
struct sock_fprog *prog = bpf;
667+
668+
int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(struct sock_fprog));
666669

667670
if (err < 0)
668-
printk(KERN_ERR BPF_ATTACH_FAIL, bpf_len, fd, -errno);
671+
printk(KERN_ERR BPF_ATTACH_FAIL, prog->len, prog->filter, fd, -errno);
669672
return err;
670673
}
671674

672-
#define DEFAULT_BPF_LEN 6
675+
int uml_vector_detach_bpf(int fd, void *bpf)
676+
{
677+
struct sock_fprog *prog = bpf;
673678

674-
void *uml_vector_default_bpf(int fd, void *mac)
679+
int err = setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, bpf, sizeof(struct sock_fprog));
680+
if (err < 0)
681+
printk(KERN_ERR BPF_DETACH_FAIL, prog->len, prog->filter, fd, -errno);
682+
return err;
683+
}
684+
void *uml_vector_default_bpf(void *mac)
675685
{
676686
struct sock_filter *bpf;
677687
uint32_t *mac1 = (uint32_t *)(mac + 2);
678688
uint16_t *mac2 = (uint16_t *) mac;
679-
struct sock_fprog bpf_prog = {
680-
.len = 6,
681-
.filter = NULL,
682-
};
689+
struct sock_fprog *bpf_prog;
683690

691+
bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
692+
if (bpf_prog) {
693+
bpf_prog->len = DEFAULT_BPF_LEN;
694+
bpf_prog->filter = NULL;
695+
} else {
696+
return NULL;
697+
}
684698
bpf = uml_kmalloc(
685699
sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL);
686-
if (bpf != NULL) {
687-
bpf_prog.filter = bpf;
700+
if (bpf) {
701+
bpf_prog->filter = bpf;
688702
/* ld [8] */
689703
bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 };
690704
/* jeq #0xMAC[2-6] jt 2 jf 5*/
@@ -697,12 +711,56 @@ void *uml_vector_default_bpf(int fd, void *mac)
697711
bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 };
698712
/* ret #0x40000 */
699713
bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 };
700-
if (uml_vector_attach_bpf(
701-
fd, &bpf_prog, sizeof(struct sock_fprog)) < 0) {
702-
kfree(bpf);
703-
bpf = NULL;
704-
}
714+
} else {
715+
kfree(bpf_prog);
716+
bpf_prog = NULL;
705717
}
706-
return bpf;
718+
return bpf_prog;
707719
}
708720

721+
/* Note - this function requires a valid mac being passed as an arg */
722+
723+
void *uml_vector_user_bpf(char *filename)
724+
{
725+
struct sock_filter *bpf;
726+
struct sock_fprog *bpf_prog;
727+
struct stat statbuf;
728+
int res, ffd = -1;
729+
730+
if (filename == NULL)
731+
return NULL;
732+
733+
if (stat(filename, &statbuf) < 0) {
734+
printk(KERN_ERR "Error %d reading bpf file", -errno);
735+
return false;
736+
}
737+
bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
738+
if (bpf_prog != NULL) {
739+
bpf_prog->len = statbuf.st_size / sizeof(struct sock_filter);
740+
bpf_prog->filter = NULL;
741+
}
742+
ffd = os_open_file(filename, of_read(OPENFLAGS()), 0);
743+
if (ffd < 0) {
744+
printk(KERN_ERR "Error %d opening bpf file", -errno);
745+
goto bpf_failed;
746+
}
747+
bpf = uml_kmalloc(statbuf.st_size, UM_GFP_KERNEL);
748+
if (bpf == NULL) {
749+
printk(KERN_ERR "Failed to allocate bpf buffer");
750+
goto bpf_failed;
751+
}
752+
bpf_prog->filter = bpf;
753+
res = os_read_file(ffd, bpf, statbuf.st_size);
754+
if (res < statbuf.st_size) {
755+
printk(KERN_ERR "Failed to read bpf program %s, error %d", filename, res);
756+
kfree(bpf);
757+
goto bpf_failed;
758+
}
759+
os_close_file(ffd);
760+
return bpf_prog;
761+
bpf_failed:
762+
if (ffd > 0)
763+
os_close_file(ffd);
764+
kfree(bpf_prog);
765+
return NULL;
766+
}

arch/um/drivers/vector_user.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#define TRANS_BESS "bess"
2929
#define TRANS_BESS_LEN strlen(TRANS_BESS)
3030

31+
#define DEFAULT_BPF_LEN 6
32+
3133
#ifndef IPPROTO_GRE
3234
#define IPPROTO_GRE 0x2F
3335
#endif
@@ -95,8 +97,10 @@ extern int uml_vector_recvmmsg(
9597
unsigned int vlen,
9698
unsigned int flags
9799
);
98-
extern void *uml_vector_default_bpf(int fd, void *mac);
99-
extern int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len);
100+
extern void *uml_vector_default_bpf(void *mac);
101+
extern void *uml_vector_user_bpf(char *filename);
102+
extern int uml_vector_attach_bpf(int fd, void *bpf);
103+
extern int uml_vector_detach_bpf(int fd, void *bpf);
100104
extern bool uml_raw_enable_qdisc_bypass(int fd);
101105
extern bool uml_raw_enable_vnet_headers(int fd);
102106
extern bool uml_tap_enable_vnet_headers(int fd);

0 commit comments

Comments
 (0)