.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | | - * Copyright (C) 2017 - Cambridge Greys Limited |
---|
| 3 | + * Copyright (C) 2017 - 2019 Cambridge Greys Limited |
---|
3 | 4 | * Copyright (C) 2011 - 2014 Cisco Systems Inc |
---|
4 | 5 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
---|
5 | 6 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and |
---|
6 | 7 | * James Leu (jleu@mindspring.net). |
---|
7 | 8 | * Copyright (C) 2001 by various other people who didn't put their name here. |
---|
8 | | - * Licensed under the GPL. |
---|
9 | 9 | */ |
---|
10 | 10 | |
---|
11 | 11 | #include <linux/version.h> |
---|
12 | | -#include <linux/bootmem.h> |
---|
| 12 | +#include <linux/memblock.h> |
---|
13 | 13 | #include <linux/etherdevice.h> |
---|
14 | 14 | #include <linux/ethtool.h> |
---|
15 | 15 | #include <linux/inetdevice.h> |
---|
.. | .. |
---|
21 | 21 | #include <linux/skbuff.h> |
---|
22 | 22 | #include <linux/slab.h> |
---|
23 | 23 | #include <linux/interrupt.h> |
---|
| 24 | +#include <linux/firmware.h> |
---|
| 25 | +#include <linux/fs.h> |
---|
| 26 | +#include <uapi/linux/filter.h> |
---|
24 | 27 | #include <init.h> |
---|
25 | 28 | #include <irq_kern.h> |
---|
26 | 29 | #include <irq_user.h> |
---|
.. | .. |
---|
43 | 46 | |
---|
44 | 47 | |
---|
45 | 48 | #define DRIVER_NAME "uml-vector" |
---|
46 | | -#define DRIVER_VERSION "01" |
---|
47 | 49 | struct vector_cmd_line_arg { |
---|
48 | 50 | struct list_head list; |
---|
49 | 51 | int unit; |
---|
.. | .. |
---|
76 | 78 | #define DEFAULT_VECTOR_SIZE 64 |
---|
77 | 79 | #define TX_SMALL_PACKET 128 |
---|
78 | 80 | #define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1) |
---|
| 81 | +#define MAX_ITERATIONS 64 |
---|
79 | 82 | |
---|
80 | 83 | static const struct { |
---|
81 | 84 | const char string[ETH_GSTRING_LEN]; |
---|
.. | .. |
---|
121 | 124 | |
---|
122 | 125 | if (mtu != NULL) { |
---|
123 | 126 | if (kstrtoul(mtu, 10, &result) == 0) |
---|
124 | | - return result; |
---|
| 127 | + if ((result < (1 << 16) - 1) && (result >= 576)) |
---|
| 128 | + return result; |
---|
125 | 129 | } |
---|
126 | 130 | return ETH_MAX_PACKET; |
---|
| 131 | +} |
---|
| 132 | + |
---|
| 133 | +static char *get_bpf_file(struct arglist *def) |
---|
| 134 | +{ |
---|
| 135 | + return uml_vector_fetch_arg(def, "bpffile"); |
---|
| 136 | +} |
---|
| 137 | + |
---|
| 138 | +static bool get_bpf_flash(struct arglist *def) |
---|
| 139 | +{ |
---|
| 140 | + char *allow = uml_vector_fetch_arg(def, "bpfflash"); |
---|
| 141 | + long result; |
---|
| 142 | + |
---|
| 143 | + if (allow != NULL) { |
---|
| 144 | + if (kstrtoul(allow, 10, &result) == 0) |
---|
| 145 | + return (allow > 0); |
---|
| 146 | + } |
---|
| 147 | + return false; |
---|
127 | 148 | } |
---|
128 | 149 | |
---|
129 | 150 | static int get_depth(struct arglist *def) |
---|
.. | .. |
---|
174 | 195 | int vec_rx = VECTOR_RX; |
---|
175 | 196 | int vec_tx = VECTOR_TX; |
---|
176 | 197 | long parsed; |
---|
| 198 | + int result = 0; |
---|
| 199 | + |
---|
| 200 | + if (transport == NULL) |
---|
| 201 | + return -EINVAL; |
---|
177 | 202 | |
---|
178 | 203 | if (vector != NULL) { |
---|
179 | 204 | if (kstrtoul(vector, 10, &parsed) == 0) { |
---|
.. | .. |
---|
184 | 209 | } |
---|
185 | 210 | } |
---|
186 | 211 | |
---|
| 212 | + if (get_bpf_flash(def)) |
---|
| 213 | + result = VECTOR_BPF_FLASH; |
---|
187 | 214 | |
---|
188 | 215 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) |
---|
189 | | - return (vec_rx | VECTOR_BPF); |
---|
| 216 | + return result; |
---|
| 217 | + if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) |
---|
| 218 | + return (result | vec_rx | VECTOR_BPF); |
---|
190 | 219 | if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) |
---|
191 | | - return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS); |
---|
192 | | - return (vec_rx | vec_tx); |
---|
| 220 | + return (result | vec_rx | vec_tx | VECTOR_QDISC_BYPASS); |
---|
| 221 | + return (result | vec_rx | vec_tx); |
---|
193 | 222 | } |
---|
194 | 223 | |
---|
195 | 224 | |
---|
.. | .. |
---|
415 | 444 | if (net_ratelimit()) |
---|
416 | 445 | netdev_err(vp->dev, "sendmmsg err=%i\n", |
---|
417 | 446 | result); |
---|
| 447 | + vp->in_error = true; |
---|
418 | 448 | result = send_len; |
---|
419 | 449 | } |
---|
420 | 450 | if (result > 0) { |
---|
.. | .. |
---|
842 | 872 | } |
---|
843 | 873 | |
---|
844 | 874 | pkt_len = uml_vector_recvmsg(vp->fds->rx_fd, &hdr, 0); |
---|
| 875 | + if (pkt_len < 0) { |
---|
| 876 | + vp->in_error = true; |
---|
| 877 | + return pkt_len; |
---|
| 878 | + } |
---|
845 | 879 | |
---|
846 | 880 | if (skb != NULL) { |
---|
847 | 881 | if (pkt_len > vp->header_size) { |
---|
.. | .. |
---|
888 | 922 | |
---|
889 | 923 | if (iov_count < 1) |
---|
890 | 924 | goto drop; |
---|
| 925 | + |
---|
891 | 926 | pkt_len = uml_vector_writev( |
---|
892 | 927 | vp->fds->tx_fd, |
---|
893 | 928 | (struct iovec *) &iov, |
---|
894 | 929 | iov_count |
---|
895 | 930 | ); |
---|
| 931 | + |
---|
| 932 | + if (pkt_len < 0) |
---|
| 933 | + goto drop; |
---|
896 | 934 | |
---|
897 | 935 | netif_trans_update(vp->dev); |
---|
898 | 936 | netif_wake_queue(vp->dev); |
---|
.. | .. |
---|
908 | 946 | drop: |
---|
909 | 947 | vp->dev->stats.tx_dropped++; |
---|
910 | 948 | consume_skb(skb); |
---|
| 949 | + if (pkt_len < 0) |
---|
| 950 | + vp->in_error = true; |
---|
911 | 951 | return pkt_len; |
---|
912 | 952 | } |
---|
913 | 953 | |
---|
.. | .. |
---|
935 | 975 | |
---|
936 | 976 | packet_count = uml_vector_recvmmsg( |
---|
937 | 977 | vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0); |
---|
| 978 | + |
---|
| 979 | + if (packet_count < 0) |
---|
| 980 | + vp->in_error = true; |
---|
938 | 981 | |
---|
939 | 982 | if (packet_count <= 0) |
---|
940 | 983 | return packet_count; |
---|
.. | .. |
---|
1005 | 1048 | static void vector_rx(struct vector_private *vp) |
---|
1006 | 1049 | { |
---|
1007 | 1050 | int err; |
---|
| 1051 | + int iter = 0; |
---|
1008 | 1052 | |
---|
1009 | 1053 | if ((vp->options & VECTOR_RX) > 0) |
---|
1010 | | - while ((err = vector_mmsg_rx(vp)) > 0) |
---|
1011 | | - ; |
---|
| 1054 | + while (((err = vector_mmsg_rx(vp)) > 0) && (iter < MAX_ITERATIONS)) |
---|
| 1055 | + iter++; |
---|
1012 | 1056 | else |
---|
1013 | | - while ((err = vector_legacy_rx(vp)) > 0) |
---|
1014 | | - ; |
---|
| 1057 | + while (((err = vector_legacy_rx(vp)) > 0) && (iter < MAX_ITERATIONS)) |
---|
| 1058 | + iter++; |
---|
1015 | 1059 | if ((err != 0) && net_ratelimit()) |
---|
1016 | 1060 | netdev_err(vp->dev, "vector_rx: error(%d)\n", err); |
---|
| 1061 | + if (iter == MAX_ITERATIONS) |
---|
| 1062 | + netdev_err(vp->dev, "vector_rx: device stuck, remote end may have closed the connection\n"); |
---|
1017 | 1063 | } |
---|
1018 | 1064 | |
---|
1019 | 1065 | static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev) |
---|
1020 | 1066 | { |
---|
1021 | 1067 | struct vector_private *vp = netdev_priv(dev); |
---|
1022 | 1068 | int queue_depth = 0; |
---|
| 1069 | + |
---|
| 1070 | + if (vp->in_error) { |
---|
| 1071 | + deactivate_fd(vp->fds->rx_fd, vp->rx_irq); |
---|
| 1072 | + if ((vp->fds->rx_fd != vp->fds->tx_fd) && (vp->tx_irq != 0)) |
---|
| 1073 | + deactivate_fd(vp->fds->tx_fd, vp->tx_irq); |
---|
| 1074 | + return NETDEV_TX_BUSY; |
---|
| 1075 | + } |
---|
1023 | 1076 | |
---|
1024 | 1077 | if ((vp->options & VECTOR_TX) == 0) { |
---|
1025 | 1078 | writev_tx(vp, skb); |
---|
.. | .. |
---|
1043 | 1096 | vector_send(vp->tx_queue); |
---|
1044 | 1097 | return NETDEV_TX_OK; |
---|
1045 | 1098 | } |
---|
1046 | | - if (skb->xmit_more) { |
---|
| 1099 | + if (netdev_xmit_more()) { |
---|
1047 | 1100 | mod_timer(&vp->tl, vp->coalesce); |
---|
1048 | 1101 | return NETDEV_TX_OK; |
---|
1049 | 1102 | } |
---|
.. | .. |
---|
1111 | 1164 | } |
---|
1112 | 1165 | tasklet_kill(&vp->tx_poll); |
---|
1113 | 1166 | if (vp->fds->rx_fd > 0) { |
---|
| 1167 | + if (vp->bpf) |
---|
| 1168 | + uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); |
---|
1114 | 1169 | os_close_file(vp->fds->rx_fd); |
---|
1115 | 1170 | vp->fds->rx_fd = -1; |
---|
1116 | 1171 | } |
---|
.. | .. |
---|
1119 | 1174 | vp->fds->tx_fd = -1; |
---|
1120 | 1175 | } |
---|
1121 | 1176 | if (vp->bpf != NULL) |
---|
1122 | | - kfree(vp->bpf); |
---|
1123 | | - if (vp->fds->remote_addr != NULL) |
---|
1124 | | - kfree(vp->fds->remote_addr); |
---|
1125 | | - if (vp->transport_data != NULL) |
---|
1126 | | - kfree(vp->transport_data); |
---|
1127 | | - if (vp->header_rxbuffer != NULL) |
---|
1128 | | - kfree(vp->header_rxbuffer); |
---|
1129 | | - if (vp->header_txbuffer != NULL) |
---|
1130 | | - kfree(vp->header_txbuffer); |
---|
| 1177 | + kfree(vp->bpf->filter); |
---|
| 1178 | + kfree(vp->bpf); |
---|
| 1179 | + vp->bpf = NULL; |
---|
| 1180 | + kfree(vp->fds->remote_addr); |
---|
| 1181 | + kfree(vp->transport_data); |
---|
| 1182 | + kfree(vp->header_rxbuffer); |
---|
| 1183 | + kfree(vp->header_txbuffer); |
---|
1131 | 1184 | if (vp->rx_queue != NULL) |
---|
1132 | 1185 | destroy_queue(vp->rx_queue); |
---|
1133 | 1186 | if (vp->tx_queue != NULL) |
---|
.. | .. |
---|
1136 | 1189 | vp->fds = NULL; |
---|
1137 | 1190 | spin_lock_irqsave(&vp->lock, flags); |
---|
1138 | 1191 | vp->opened = false; |
---|
| 1192 | + vp->in_error = false; |
---|
1139 | 1193 | spin_unlock_irqrestore(&vp->lock, flags); |
---|
1140 | 1194 | return 0; |
---|
1141 | 1195 | } |
---|
.. | .. |
---|
1157 | 1211 | netif_start_queue(vp->dev); |
---|
1158 | 1212 | netif_wake_queue(vp->dev); |
---|
1159 | 1213 | } |
---|
| 1214 | + |
---|
1160 | 1215 | static int vector_net_open(struct net_device *dev) |
---|
1161 | 1216 | { |
---|
1162 | 1217 | struct vector_private *vp = netdev_priv(dev); |
---|
.. | .. |
---|
1171 | 1226 | } |
---|
1172 | 1227 | vp->opened = true; |
---|
1173 | 1228 | spin_unlock_irqrestore(&vp->lock, flags); |
---|
| 1229 | + |
---|
| 1230 | + vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed)); |
---|
1174 | 1231 | |
---|
1175 | 1232 | vp->fds = uml_vector_user_open(vp->unit, vp->parsed); |
---|
1176 | 1233 | |
---|
.. | .. |
---|
1243 | 1300 | if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd)) |
---|
1244 | 1301 | vp->options |= VECTOR_BPF; |
---|
1245 | 1302 | } |
---|
1246 | | - if ((vp->options & VECTOR_BPF) != 0) |
---|
1247 | | - vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr); |
---|
| 1303 | + if (((vp->options & VECTOR_BPF) != 0) && (vp->bpf == NULL)) |
---|
| 1304 | + vp->bpf = uml_vector_default_bpf(dev->dev_addr); |
---|
| 1305 | + |
---|
| 1306 | + if (vp->bpf != NULL) |
---|
| 1307 | + uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); |
---|
1248 | 1308 | |
---|
1249 | 1309 | netif_start_queue(dev); |
---|
1250 | 1310 | |
---|
.. | .. |
---|
1274 | 1334 | return; |
---|
1275 | 1335 | } |
---|
1276 | 1336 | |
---|
1277 | | -static void vector_net_tx_timeout(struct net_device *dev) |
---|
| 1337 | +static void vector_net_tx_timeout(struct net_device *dev, unsigned int txqueue) |
---|
1278 | 1338 | { |
---|
1279 | 1339 | struct vector_private *vp = netdev_priv(dev); |
---|
1280 | 1340 | |
---|
.. | .. |
---|
1320 | 1380 | struct ethtool_drvinfo *info) |
---|
1321 | 1381 | { |
---|
1322 | 1382 | strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); |
---|
1323 | | - strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); |
---|
| 1383 | +} |
---|
| 1384 | + |
---|
| 1385 | +static int vector_net_load_bpf_flash(struct net_device *dev, |
---|
| 1386 | + struct ethtool_flash *efl) |
---|
| 1387 | +{ |
---|
| 1388 | + struct vector_private *vp = netdev_priv(dev); |
---|
| 1389 | + struct vector_device *vdevice; |
---|
| 1390 | + const struct firmware *fw; |
---|
| 1391 | + int result = 0; |
---|
| 1392 | + |
---|
| 1393 | + if (!(vp->options & VECTOR_BPF_FLASH)) { |
---|
| 1394 | + netdev_err(dev, "loading firmware not permitted: %s\n", efl->data); |
---|
| 1395 | + return -1; |
---|
| 1396 | + } |
---|
| 1397 | + |
---|
| 1398 | + spin_lock(&vp->lock); |
---|
| 1399 | + |
---|
| 1400 | + if (vp->bpf != NULL) { |
---|
| 1401 | + if (vp->opened) |
---|
| 1402 | + uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); |
---|
| 1403 | + kfree(vp->bpf->filter); |
---|
| 1404 | + vp->bpf->filter = NULL; |
---|
| 1405 | + } else { |
---|
| 1406 | + vp->bpf = kmalloc(sizeof(struct sock_fprog), GFP_ATOMIC); |
---|
| 1407 | + if (vp->bpf == NULL) { |
---|
| 1408 | + netdev_err(dev, "failed to allocate memory for firmware\n"); |
---|
| 1409 | + goto flash_fail; |
---|
| 1410 | + } |
---|
| 1411 | + } |
---|
| 1412 | + |
---|
| 1413 | + vdevice = find_device(vp->unit); |
---|
| 1414 | + |
---|
| 1415 | + if (request_firmware(&fw, efl->data, &vdevice->pdev.dev)) |
---|
| 1416 | + goto flash_fail; |
---|
| 1417 | + |
---|
| 1418 | + vp->bpf->filter = kmemdup(fw->data, fw->size, GFP_ATOMIC); |
---|
| 1419 | + if (!vp->bpf->filter) |
---|
| 1420 | + goto free_buffer; |
---|
| 1421 | + |
---|
| 1422 | + vp->bpf->len = fw->size / sizeof(struct sock_filter); |
---|
| 1423 | + release_firmware(fw); |
---|
| 1424 | + |
---|
| 1425 | + if (vp->opened) |
---|
| 1426 | + result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); |
---|
| 1427 | + |
---|
| 1428 | + spin_unlock(&vp->lock); |
---|
| 1429 | + |
---|
| 1430 | + return result; |
---|
| 1431 | + |
---|
| 1432 | +free_buffer: |
---|
| 1433 | + release_firmware(fw); |
---|
| 1434 | + |
---|
| 1435 | +flash_fail: |
---|
| 1436 | + spin_unlock(&vp->lock); |
---|
| 1437 | + if (vp->bpf != NULL) |
---|
| 1438 | + kfree(vp->bpf->filter); |
---|
| 1439 | + kfree(vp->bpf); |
---|
| 1440 | + vp->bpf = NULL; |
---|
| 1441 | + return -1; |
---|
1324 | 1442 | } |
---|
1325 | 1443 | |
---|
1326 | 1444 | static void vector_get_ringparam(struct net_device *netdev, |
---|
.. | .. |
---|
1391 | 1509 | } |
---|
1392 | 1510 | |
---|
1393 | 1511 | static const struct ethtool_ops vector_net_ethtool_ops = { |
---|
| 1512 | + .supported_coalesce_params = ETHTOOL_COALESCE_TX_USECS, |
---|
1394 | 1513 | .get_drvinfo = vector_net_get_drvinfo, |
---|
1395 | 1514 | .get_link = ethtool_op_get_link, |
---|
1396 | 1515 | .get_ts_info = ethtool_op_get_ts_info, |
---|
.. | .. |
---|
1400 | 1519 | .get_ethtool_stats = vector_get_ethtool_stats, |
---|
1401 | 1520 | .get_coalesce = vector_get_coalesce, |
---|
1402 | 1521 | .set_coalesce = vector_set_coalesce, |
---|
| 1522 | + .flash_device = vector_net_load_bpf_flash, |
---|
1403 | 1523 | }; |
---|
1404 | 1524 | |
---|
1405 | 1525 | |
---|
.. | .. |
---|
1503 | 1623 | .transport_data = NULL, |
---|
1504 | 1624 | .in_write_poll = false, |
---|
1505 | 1625 | .coalesce = 2, |
---|
1506 | | - .req_size = get_req_size(def) |
---|
1507 | | - }); |
---|
| 1626 | + .req_size = get_req_size(def), |
---|
| 1627 | + .in_error = false, |
---|
| 1628 | + .bpf = NULL |
---|
| 1629 | + }); |
---|
1508 | 1630 | |
---|
1509 | 1631 | dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST); |
---|
1510 | 1632 | tasklet_init(&vp->tx_poll, vector_tx_poll, (unsigned long)vp); |
---|
.. | .. |
---|
1580 | 1702 | str, error); |
---|
1581 | 1703 | return 1; |
---|
1582 | 1704 | } |
---|
1583 | | - new = alloc_bootmem(sizeof(*new)); |
---|
| 1705 | + new = memblock_alloc(sizeof(*new), SMP_CACHE_BYTES); |
---|
| 1706 | + if (!new) |
---|
| 1707 | + panic("%s: Failed to allocate %zu bytes\n", __func__, |
---|
| 1708 | + sizeof(*new)); |
---|
1584 | 1709 | INIT_LIST_HEAD(&new->list); |
---|
1585 | 1710 | new->unit = n; |
---|
1586 | 1711 | new->arguments = str; |
---|