diff options
author | Anton Ivanov <anton.ivanov@cambridgegreys.com> | 2019-08-09 03:40:17 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2019-09-15 15:37:08 -0400 |
commit | b3b8ca2a1b63713f59e8d7ad772b09bcd8dc9048 (patch) | |
tree | 0011db879e9f96c8a9e1404cf9227dca9aa2445b /arch/um/drivers | |
parent | 03e46a4d5b439079286e5e0c5211cee33e480c3a (diff) |
um: Add legacy tap support and rename existing vector to hybrid
1. Adds legacy tap support
2. Renames tap+raw as hybrid
Signed-off-by: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/drivers')
-rw-r--r-- | arch/um/drivers/vector_kern.c | 2 | ||||
-rw-r--r-- | arch/um/drivers/vector_transports.c | 29 | ||||
-rw-r--r-- | arch/um/drivers/vector_user.c | 203 | ||||
-rw-r--r-- | arch/um/drivers/vector_user.h | 4 |
4 files changed, 151 insertions, 87 deletions
diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index e190e4ca52e1..8fa094770965 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c | |||
@@ -186,6 +186,8 @@ static int get_transport_options(struct arglist *def) | |||
186 | 186 | ||
187 | 187 | ||
188 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) | 188 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) |
189 | return 0; | ||
190 | if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) | ||
189 | return (vec_rx | VECTOR_BPF); | 191 | return (vec_rx | VECTOR_BPF); |
190 | if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) | 192 | if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) |
191 | return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS); | 193 | return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS); |
diff --git a/arch/um/drivers/vector_transports.c b/arch/um/drivers/vector_transports.c index 77e4ebc206ae..2999f3bd1781 100644 --- a/arch/um/drivers/vector_transports.c +++ b/arch/um/drivers/vector_transports.c | |||
@@ -418,7 +418,7 @@ static int build_raw_transport_data(struct vector_private *vp) | |||
418 | return 0; | 418 | return 0; |
419 | } | 419 | } |
420 | 420 | ||
421 | static int build_tap_transport_data(struct vector_private *vp) | 421 | static int build_hybrid_transport_data(struct vector_private *vp) |
422 | { | 422 | { |
423 | if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { | 423 | if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { |
424 | vp->form_header = &raw_form_header; | 424 | vp->form_header = &raw_form_header; |
@@ -432,7 +432,7 @@ static int build_tap_transport_data(struct vector_private *vp) | |||
432 | NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); | 432 | NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); |
433 | netdev_info( | 433 | netdev_info( |
434 | vp->dev, | 434 | vp->dev, |
435 | "tap/raw: using vnet headers for tso and tx/rx checksum" | 435 | "tap/raw hybrid: using vnet headers for tso and tx/rx checksum" |
436 | ); | 436 | ); |
437 | } else { | 437 | } else { |
438 | return 0; /* do not try to enable tap too if raw failed */ | 438 | return 0; /* do not try to enable tap too if raw failed */ |
@@ -442,6 +442,29 @@ static int build_tap_transport_data(struct vector_private *vp) | |||
442 | return -1; | 442 | return -1; |
443 | } | 443 | } |
444 | 444 | ||
445 | static int build_tap_transport_data(struct vector_private *vp) | ||
446 | { | ||
447 | /* "Pure" tap uses the same fd for rx and tx */ | ||
448 | if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) { | ||
449 | vp->form_header = &raw_form_header; | ||
450 | vp->verify_header = &raw_verify_header; | ||
451 | vp->header_size = sizeof(struct virtio_net_hdr); | ||
452 | vp->rx_header_size = sizeof(struct virtio_net_hdr); | ||
453 | vp->dev->hw_features |= | ||
454 | (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); | ||
455 | vp->dev->features |= | ||
456 | (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | | ||
457 | NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); | ||
458 | netdev_info( | ||
459 | vp->dev, | ||
460 | "tap: using vnet headers for tso and tx/rx checksum" | ||
461 | ); | ||
462 | return 0; | ||
463 | } | ||
464 | return -1; | ||
465 | } | ||
466 | |||
467 | |||
445 | int build_transport_data(struct vector_private *vp) | 468 | int build_transport_data(struct vector_private *vp) |
446 | { | 469 | { |
447 | char *transport = uml_vector_fetch_arg(vp->parsed, "transport"); | 470 | char *transport = uml_vector_fetch_arg(vp->parsed, "transport"); |
@@ -454,6 +477,8 @@ int build_transport_data(struct vector_private *vp) | |||
454 | return build_raw_transport_data(vp); | 477 | return build_raw_transport_data(vp); |
455 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) | 478 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) |
456 | return build_tap_transport_data(vp); | 479 | return build_tap_transport_data(vp); |
480 | if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) | ||
481 | return build_hybrid_transport_data(vp); | ||
457 | return 0; | 482 | return 0; |
458 | } | 483 | } |
459 | 484 | ||
diff --git a/arch/um/drivers/vector_user.c b/arch/um/drivers/vector_user.c index b3f7b3ca896d..0ada22f82965 100644 --- a/arch/um/drivers/vector_user.c +++ b/arch/um/drivers/vector_user.c | |||
@@ -114,12 +114,76 @@ cleanup: | |||
114 | 114 | ||
115 | #define PATH_NET_TUN "/dev/net/tun" | 115 | #define PATH_NET_TUN "/dev/net/tun" |
116 | 116 | ||
117 | static struct vector_fds *user_init_tap_fds(struct arglist *ifspec) | 117 | |
118 | static int create_tap_fd(char *iface) | ||
118 | { | 119 | { |
119 | struct ifreq ifr; | 120 | struct ifreq ifr; |
120 | int fd = -1; | 121 | int fd = -1; |
121 | struct sockaddr_ll sock; | ||
122 | int err = -ENOMEM, offload; | 122 | int err = -ENOMEM, offload; |
123 | |||
124 | fd = open(PATH_NET_TUN, O_RDWR); | ||
125 | if (fd < 0) { | ||
126 | printk(UM_KERN_ERR "uml_tap: failed to open tun device\n"); | ||
127 | goto tap_fd_cleanup; | ||
128 | } | ||
129 | memset(&ifr, 0, sizeof(ifr)); | ||
130 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; | ||
131 | strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); | ||
132 | |||
133 | err = ioctl(fd, TUNSETIFF, (void *) &ifr); | ||
134 | if (err != 0) { | ||
135 | printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n"); | ||
136 | goto tap_fd_cleanup; | ||
137 | } | ||
138 | |||
139 | offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6; | ||
140 | ioctl(fd, TUNSETOFFLOAD, offload); | ||
141 | return fd; | ||
142 | tap_fd_cleanup: | ||
143 | if (fd >= 0) | ||
144 | os_close_file(fd); | ||
145 | return err; | ||
146 | } | ||
147 | |||
148 | static int create_raw_fd(char *iface, int flags, int proto) | ||
149 | { | ||
150 | struct ifreq ifr; | ||
151 | int fd = -1; | ||
152 | struct sockaddr_ll sock; | ||
153 | int err = -ENOMEM; | ||
154 | |||
155 | fd = socket(AF_PACKET, SOCK_RAW, flags); | ||
156 | if (fd == -1) { | ||
157 | err = -errno; | ||
158 | goto raw_fd_cleanup; | ||
159 | } | ||
160 | memset(&ifr, 0, sizeof(ifr)); | ||
161 | strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); | ||
162 | if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) { | ||
163 | err = -errno; | ||
164 | goto raw_fd_cleanup; | ||
165 | } | ||
166 | |||
167 | sock.sll_family = AF_PACKET; | ||
168 | sock.sll_protocol = htons(proto); | ||
169 | sock.sll_ifindex = ifr.ifr_ifindex; | ||
170 | |||
171 | if (bind(fd, | ||
172 | (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { | ||
173 | err = -errno; | ||
174 | goto raw_fd_cleanup; | ||
175 | } | ||
176 | return fd; | ||
177 | raw_fd_cleanup: | ||
178 | printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); | ||
179 | if (fd >= 0) | ||
180 | os_close_file(fd); | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | static struct vector_fds *user_init_tap_fds(struct arglist *ifspec) | ||
185 | { | ||
186 | int fd = -1; | ||
123 | char *iface; | 187 | char *iface; |
124 | struct vector_fds *result = NULL; | 188 | struct vector_fds *result = NULL; |
125 | 189 | ||
@@ -141,117 +205,88 @@ static struct vector_fds *user_init_tap_fds(struct arglist *ifspec) | |||
141 | 205 | ||
142 | /* TAP */ | 206 | /* TAP */ |
143 | 207 | ||
144 | fd = open(PATH_NET_TUN, O_RDWR); | 208 | fd = create_tap_fd(iface); |
145 | if (fd < 0) { | 209 | if (fd < 0) { |
146 | printk(UM_KERN_ERR "uml_tap: failed to open tun device\n"); | 210 | printk(UM_KERN_ERR "uml_tap: failed to create tun interface\n"); |
147 | goto tap_cleanup; | 211 | goto tap_cleanup; |
148 | } | 212 | } |
149 | result->tx_fd = fd; | 213 | result->tx_fd = fd; |
150 | memset(&ifr, 0, sizeof(ifr)); | 214 | result->rx_fd = fd; |
151 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; | 215 | return result; |
152 | strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); | 216 | tap_cleanup: |
217 | printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd); | ||
218 | if (result != NULL) | ||
219 | kfree(result); | ||
220 | return NULL; | ||
221 | } | ||
153 | 222 | ||
154 | err = ioctl(fd, TUNSETIFF, (void *) &ifr); | 223 | static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec) |
155 | if (err != 0) { | 224 | { |
156 | printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n"); | 225 | char *iface; |
157 | goto tap_cleanup; | 226 | struct vector_fds *result = NULL; |
227 | |||
228 | iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); | ||
229 | if (iface == NULL) { | ||
230 | printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n"); | ||
231 | goto hybrid_cleanup; | ||
158 | } | 232 | } |
159 | 233 | ||
160 | offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6; | 234 | result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); |
161 | ioctl(fd, TUNSETOFFLOAD, offload); | 235 | if (result == NULL) { |
236 | printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); | ||
237 | goto hybrid_cleanup; | ||
238 | } | ||
239 | result->rx_fd = -1; | ||
240 | result->tx_fd = -1; | ||
241 | result->remote_addr = NULL; | ||
242 | result->remote_addr_size = 0; | ||
162 | 243 | ||
163 | /* RAW */ | 244 | /* TAP */ |
164 | 245 | ||
165 | fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | 246 | result->tx_fd = create_tap_fd(iface); |
166 | if (fd == -1) { | 247 | if (result->tx_fd < 0) { |
167 | printk(UM_KERN_ERR | 248 | printk(UM_KERN_ERR "uml_tap: failed to create tun interface: %i\n", result->tx_fd); |
168 | "uml_tap: failed to create socket: %i\n", -errno); | 249 | goto hybrid_cleanup; |
169 | goto tap_cleanup; | ||
170 | } | ||
171 | result->rx_fd = fd; | ||
172 | memset(&ifr, 0, sizeof(ifr)); | ||
173 | strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); | ||
174 | if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) { | ||
175 | printk(UM_KERN_ERR | ||
176 | "uml_tap: failed to set interface: %i\n", -errno); | ||
177 | goto tap_cleanup; | ||
178 | } | 250 | } |
179 | 251 | ||
180 | sock.sll_family = AF_PACKET; | 252 | /* RAW */ |
181 | sock.sll_protocol = htons(ETH_P_ALL); | ||
182 | sock.sll_ifindex = ifr.ifr_ifindex; | ||
183 | 253 | ||
184 | if (bind(fd, | 254 | result->rx_fd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL); |
185 | (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { | 255 | if (result->rx_fd == -1) { |
186 | printk(UM_KERN_ERR | 256 | printk(UM_KERN_ERR |
187 | "user_init_tap: failed to bind raw pair, err %d\n", | 257 | "uml_tap: failed to create paired raw socket: %i\n", result->rx_fd); |
188 | -errno); | 258 | goto hybrid_cleanup; |
189 | goto tap_cleanup; | ||
190 | } | 259 | } |
191 | return result; | 260 | return result; |
192 | tap_cleanup: | 261 | hybrid_cleanup: |
193 | printk(UM_KERN_ERR "user_init_tap: init failed, error %d", err); | 262 | printk(UM_KERN_ERR "user_init_hybrid: init failed"); |
194 | if (result != NULL) { | 263 | if (result != NULL) |
195 | if (result->rx_fd >= 0) | ||
196 | os_close_file(result->rx_fd); | ||
197 | if (result->tx_fd >= 0) | ||
198 | os_close_file(result->tx_fd); | ||
199 | kfree(result); | 264 | kfree(result); |
200 | } | ||
201 | return NULL; | 265 | return NULL; |
202 | } | 266 | } |
203 | 267 | ||
204 | 268 | ||
205 | static struct vector_fds *user_init_raw_fds(struct arglist *ifspec) | 269 | static struct vector_fds *user_init_raw_fds(struct arglist *ifspec) |
206 | { | 270 | { |
207 | struct ifreq ifr; | ||
208 | int rxfd = -1, txfd = -1; | 271 | int rxfd = -1, txfd = -1; |
209 | struct sockaddr_ll sock; | ||
210 | int err = -ENOMEM; | 272 | int err = -ENOMEM; |
211 | char *iface; | 273 | char *iface; |
212 | struct vector_fds *result = NULL; | 274 | struct vector_fds *result = NULL; |
213 | 275 | ||
214 | iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); | 276 | iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); |
215 | if (iface == NULL) | 277 | if (iface == NULL) |
216 | goto cleanup; | 278 | goto raw_cleanup; |
217 | 279 | ||
218 | rxfd = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); | 280 | rxfd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL); |
219 | if (rxfd == -1) { | 281 | if (rxfd == -1) { |
220 | err = -errno; | 282 | err = -errno; |
221 | goto cleanup; | 283 | goto raw_cleanup; |
222 | } | 284 | } |
223 | txfd = socket(AF_PACKET, SOCK_RAW, 0); /* Turn off RX on this fd */ | 285 | txfd = create_raw_fd(iface, 0, ETH_P_IP); /* Turn off RX on this fd */ |
224 | if (txfd == -1) { | 286 | if (txfd == -1) { |
225 | err = -errno; | 287 | err = -errno; |
226 | goto cleanup; | 288 | goto raw_cleanup; |
227 | } | ||
228 | memset(&ifr, 0, sizeof(ifr)); | ||
229 | strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); | ||
230 | if (ioctl(rxfd, SIOCGIFINDEX, (void *) &ifr) < 0) { | ||
231 | err = -errno; | ||
232 | goto cleanup; | ||
233 | } | ||
234 | |||
235 | sock.sll_family = AF_PACKET; | ||
236 | sock.sll_protocol = htons(ETH_P_ALL); | ||
237 | sock.sll_ifindex = ifr.ifr_ifindex; | ||
238 | |||
239 | if (bind(rxfd, | ||
240 | (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { | ||
241 | err = -errno; | ||
242 | goto cleanup; | ||
243 | } | 289 | } |
244 | |||
245 | sock.sll_family = AF_PACKET; | ||
246 | sock.sll_protocol = htons(ETH_P_IP); | ||
247 | sock.sll_ifindex = ifr.ifr_ifindex; | ||
248 | |||
249 | if (bind(txfd, | ||
250 | (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { | ||
251 | err = -errno; | ||
252 | goto cleanup; | ||
253 | } | ||
254 | |||
255 | result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); | 290 | result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); |
256 | if (result != NULL) { | 291 | if (result != NULL) { |
257 | result->rx_fd = rxfd; | 292 | result->rx_fd = rxfd; |
@@ -260,13 +295,10 @@ static struct vector_fds *user_init_raw_fds(struct arglist *ifspec) | |||
260 | result->remote_addr_size = 0; | 295 | result->remote_addr_size = 0; |
261 | } | 296 | } |
262 | return result; | 297 | return result; |
263 | cleanup: | 298 | raw_cleanup: |
264 | printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); | 299 | printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); |
265 | if (rxfd >= 0) | 300 | if (result != NULL) |
266 | os_close_file(rxfd); | 301 | kfree(result); |
267 | if (txfd >= 0) | ||
268 | os_close_file(txfd); | ||
269 | kfree(result); | ||
270 | return NULL; | 302 | return NULL; |
271 | } | 303 | } |
272 | 304 | ||
@@ -456,6 +488,8 @@ struct vector_fds *uml_vector_user_open( | |||
456 | } | 488 | } |
457 | if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) | 489 | if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) |
458 | return user_init_raw_fds(parsed); | 490 | return user_init_raw_fds(parsed); |
491 | if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) | ||
492 | return user_init_hybrid_fds(parsed); | ||
459 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) | 493 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) |
460 | return user_init_tap_fds(parsed); | 494 | return user_init_tap_fds(parsed); |
461 | if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0) | 495 | if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0) |
@@ -482,8 +516,9 @@ int uml_vector_sendmsg(int fd, void *hdr, int flags) | |||
482 | int uml_vector_recvmsg(int fd, void *hdr, int flags) | 516 | int uml_vector_recvmsg(int fd, void *hdr, int flags) |
483 | { | 517 | { |
484 | int n; | 518 | int n; |
519 | struct msghdr *msg = (struct msghdr *) hdr; | ||
485 | 520 | ||
486 | CATCH_EINTR(n = recvmsg(fd, (struct msghdr *) hdr, flags)); | 521 | CATCH_EINTR(n = readv(fd, msg->msg_iov, msg->msg_iovlen)); |
487 | if ((n < 0) && (errno == EAGAIN)) | 522 | if ((n < 0) && (errno == EAGAIN)) |
488 | return 0; | 523 | return 0; |
489 | if (n >= 0) | 524 | if (n >= 0) |
diff --git a/arch/um/drivers/vector_user.h b/arch/um/drivers/vector_user.h index d7cbff73b7ff..6bf50cf78ad0 100644 --- a/arch/um/drivers/vector_user.h +++ b/arch/um/drivers/vector_user.h | |||
@@ -16,13 +16,15 @@ | |||
16 | #define TRANS_TAP "tap" | 16 | #define TRANS_TAP "tap" |
17 | #define TRANS_TAP_LEN strlen(TRANS_TAP) | 17 | #define TRANS_TAP_LEN strlen(TRANS_TAP) |
18 | 18 | ||
19 | |||
20 | #define TRANS_GRE "gre" | 19 | #define TRANS_GRE "gre" |
21 | #define TRANS_GRE_LEN strlen(TRANS_RAW) | 20 | #define TRANS_GRE_LEN strlen(TRANS_RAW) |
22 | 21 | ||
23 | #define TRANS_L2TPV3 "l2tpv3" | 22 | #define TRANS_L2TPV3 "l2tpv3" |
24 | #define TRANS_L2TPV3_LEN strlen(TRANS_L2TPV3) | 23 | #define TRANS_L2TPV3_LEN strlen(TRANS_L2TPV3) |
25 | 24 | ||
25 | #define TRANS_HYBRID "hybrid" | ||
26 | #define TRANS_HYBRID_LEN strlen(TRANS_HYBRID) | ||
27 | |||
26 | #ifndef IPPROTO_GRE | 28 | #ifndef IPPROTO_GRE |
27 | #define IPPROTO_GRE 0x2F | 29 | #define IPPROTO_GRE 0x2F |
28 | #endif | 30 | #endif |