diff options
Diffstat (limited to 'tap.h')
-rw-r--r-- | tap.h | 116 |
1 files changed, 77 insertions, 39 deletions
@@ -6,73 +6,104 @@ #ifndef TAP_H #define TAP_H +/** L2_MAX_LEN_PASTA - Maximum frame length for pasta mode (with L2 header) + * + * The kernel tuntap device imposes a maximum frame size of 65535 including + * 'hard_header_len' (14 bytes for L2 Ethernet in the case of "tap" mode). + */ +#define L2_MAX_LEN_PASTA USHRT_MAX + +/** L2_MAX_LEN_PASST - Maximum frame length for passt mode (with L2 header) + * + * The only structural limit the QEMU socket protocol imposes on frames is + * (2^32-1) bytes, but that would be ludicrously long in practice. For now, + * limit it somewhat arbitrarily to 65535 bytes. FIXME: Work out an appropriate + * limit with more precision. + */ +#define L2_MAX_LEN_PASST USHRT_MAX + +/** L2_MAX_LEN_VU - Maximum frame length for vhost-user mode (with L2 header) + * + * vhost-user allows multiple buffers per frame, each of which can be quite + * large, so the inherent frame size limit is rather large. Much larger than is + * actually useful for IP. For now limit arbitrarily to 65535 bytes. FIXME: + * Work out an appropriate limit with more precision. + */ +#define L2_MAX_LEN_VU USHRT_MAX + +struct udphdr; + /** - * struct tap_hdr - L2 and tap specific headers + * struct tap_hdr - tap backend specific headers * @vnet_len: Frame length (for qemu socket transport) - * @eh: Ethernet header */ struct tap_hdr { uint32_t vnet_len; - struct ethhdr eh; } __attribute__((packed)); -#define TAP_HDR_INIT(proto) { .eh.h_proto = htons_constant(proto) } - -static inline size_t tap_hdr_len_(const struct ctx *c) -{ - if (c->mode == MODE_PASST) - return sizeof(struct tap_hdr); - else - return sizeof(struct ethhdr); -} - /** - * tap_frame_base() - Find start of tap frame + * tap_hdr_iov() - struct iovec for a tap header * @c: Execution context - * @taph: Pointer to L2 and tap specific header buffer + * @taph: Pointer to tap specific header buffer * - * Returns: pointer to the start of tap frame - suitable for an - * iov_base to be passed to tap_send_frames()) + * Returns: A struct iovec covering the correct portion of @taph to use as the + * tap specific header in the current configuration. */ -static inline void *tap_frame_base(const struct ctx *c, struct tap_hdr *taph) +static inline struct iovec tap_hdr_iov(const struct ctx *c, + struct tap_hdr *thdr) { - return (char *)(taph + 1) - tap_hdr_len_(c); + return (struct iovec){ + .iov_base = thdr, + .iov_len = c->mode == MODE_PASST ? sizeof(*thdr) : 0, + }; } /** - * tap_frame_len() - Finalize tap frame and return total length - * @c: Execution context - * @taph: Tap header to finalize - * @plen: L3 packet length (excludes L2 and tap specific headers) - * - * Returns: length of the tap frame including L2 and tap specific - * headers - suitable for an iov_len to be passed to - * tap_send_frames() + * tap_hdr_update() - Update the tap specific header for a frame + * @taph: Tap specific header buffer to update + * @l2len: Frame length (including L2 headers) */ -static inline size_t tap_frame_len(const struct ctx *c, struct tap_hdr *taph, - size_t plen) +static inline void tap_hdr_update(struct tap_hdr *thdr, size_t l2len) { - if (c->mode == MODE_PASST) - taph->vnet_len = htonl(plen + sizeof(taph->eh)); - return plen + tap_hdr_len_(c); + if (thdr) + thdr->vnet_len = htonl(l2len); } -struct in_addr tap_ip4_daddr(const struct ctx *c); +unsigned long tap_l2_max_len(const struct ctx *c); +void *tap_push_l2h(const struct ctx *c, void *buf, uint16_t proto); +void *tap_push_ip4h(struct iphdr *ip4h, struct in_addr src, + struct in_addr dst, size_t l4len, uint8_t proto); +void *tap_push_uh4(struct udphdr *uh, struct in_addr src, in_port_t sport, + struct in_addr dst, in_port_t dport, + const void *in, size_t dlen); +void *tap_push_uh6(struct udphdr *uh, + const struct in6_addr *src, in_port_t sport, + const struct in6_addr *dst, in_port_t dport, + void *in, size_t dlen); +void *tap_push_ip4h(struct iphdr *ip4h, struct in_addr src, + struct in_addr dst, size_t l4len, uint8_t proto); +void *tap_push_ip6h(struct ipv6hdr *ip6h, + const struct in6_addr *src, + const struct in6_addr *dst, + size_t l4len, uint8_t proto, uint32_t flow); void tap_udp4_send(const struct ctx *c, struct in_addr src, in_port_t sport, struct in_addr dst, in_port_t dport, - const void *in, size_t len); + const void *in, size_t dlen); void tap_icmp4_send(const struct ctx *c, struct in_addr src, struct in_addr dst, - const void *in, size_t len); + const void *in, size_t l4len); const struct in6_addr *tap_ip6_daddr(const struct ctx *c, const struct in6_addr *src); +void *tap_push_ip6h(struct ipv6hdr *ip6h, + const struct in6_addr *src, const struct in6_addr *dst, + size_t l4len, uint8_t proto, uint32_t flow); void tap_udp6_send(const struct ctx *c, const struct in6_addr *src, in_port_t sport, const struct in6_addr *dst, in_port_t dport, - uint32_t flow, const void *in, size_t len); + uint32_t flow, void *in, size_t dlen); void tap_icmp6_send(const struct ctx *c, const struct in6_addr *src, const struct in6_addr *dst, - const void *in, size_t len); -void tap_send_single(const struct ctx *c, const void *data, size_t len); + const void *in, size_t l4len); +void tap_send_single(const struct ctx *c, const void *data, size_t l2len); size_t tap_send_frames(const struct ctx *c, const struct iovec *iov, size_t bufs_per_frame, size_t nframes); void eth_update_mac(struct ethhdr *eh, @@ -82,6 +113,13 @@ void tap_handler_pasta(struct ctx *c, uint32_t events, const struct timespec *now); void tap_handler_passt(struct ctx *c, uint32_t events, const struct timespec *now); -void tap_sock_init(struct ctx *c); +int tap_sock_unix_open(char *sock_path); +void tap_sock_reset(struct ctx *c); +void tap_sock_update_pool(void *base, size_t size); +void tap_backend_init(struct ctx *c); +void tap_flush_pools(void); +void tap_handler(struct ctx *c, const struct timespec *now); +void tap_add_packet(struct ctx *c, ssize_t l2len, char *p, + const struct timespec *now); #endif /* TAP_H */ |