summary refs log tree commit diff stats
path: root/include/net
diff options
context:
space:
mode:
Diffstat (limited to 'include/net')
-rw-r--r--include/net/checksum.h49
-rw-r--r--include/net/eth.h158
-rw-r--r--include/net/net.h19
3 files changed, 181 insertions, 45 deletions
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 7de1acb79a..7df472c2fe 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -18,6 +18,7 @@
 #ifndef QEMU_NET_CHECKSUM_H
 #define QEMU_NET_CHECKSUM_H
 
+#include "qemu/bswap.h"
 struct iovec;
 
 uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq);
@@ -45,9 +46,55 @@ net_raw_checksum(uint8_t *data, int length)
  * @iov_cnt: number of array elements
  * @iov_off: starting iov offset for checksumming
  * @size: length of data to be checksummed
+ * @csum_offset: offset of the checksum chunk
  */
 uint32_t net_checksum_add_iov(const struct iovec *iov,
                               const unsigned int iov_cnt,
-                              uint32_t iov_off, uint32_t size);
+                              uint32_t iov_off, uint32_t size,
+                              uint32_t csum_offset);
+
+typedef struct toeplitz_key_st {
+    uint32_t leftmost_32_bits;
+    uint8_t *next_byte;
+} net_toeplitz_key;
+
+static inline
+void net_toeplitz_key_init(net_toeplitz_key *key, uint8_t *key_bytes)
+{
+    key->leftmost_32_bits = be32_to_cpu(*(uint32_t *)key_bytes);
+    key->next_byte = key_bytes + sizeof(uint32_t);
+}
+
+static inline
+void net_toeplitz_add(uint32_t *result,
+                      uint8_t *input,
+                      uint32_t len,
+                      net_toeplitz_key *key)
+{
+    register uint32_t accumulator = *result;
+    register uint32_t leftmost_32_bits = key->leftmost_32_bits;
+    register uint32_t byte;
+
+    for (byte = 0; byte < len; byte++) {
+        register uint8_t input_byte = input[byte];
+        register uint8_t key_byte = *(key->next_byte++);
+        register uint8_t bit;
+
+        for (bit = 0; bit < 8; bit++) {
+            if (input_byte & (1 << 7)) {
+                accumulator ^= leftmost_32_bits;
+            }
+
+            leftmost_32_bits =
+                (leftmost_32_bits << 1) | ((key_byte & (1 << 7)) >> 7);
+
+            input_byte <<= 1;
+            key_byte <<= 1;
+        }
+    }
+
+    key->leftmost_32_bits = leftmost_32_bits;
+    *result = accumulator;
+}
 
 #endif /* QEMU_NET_CHECKSUM_H */
diff --git a/include/net/eth.h b/include/net/eth.h
index 18d0be3b16..2013175857 100644
--- a/include/net/eth.h
+++ b/include/net/eth.h
@@ -67,6 +67,16 @@ typedef struct tcp_header {
     uint16_t th_urp;            /* urgent pointer */
 } tcp_header;
 
+#define TCP_FLAGS_ONLY(flags) ((flags) & 0x3f)
+
+#define TCP_HEADER_FLAGS(tcp) \
+    TCP_FLAGS_ONLY(be16_to_cpu((tcp)->th_offset_flags))
+
+#define TCP_FLAG_ACK  0x10
+
+#define TCP_HEADER_DATA_OFFSET(tcp) \
+    (((be16_to_cpu((tcp)->th_offset_flags) >> 12) & 0xf) << 2)
+
 typedef struct udp_header {
     uint16_t uh_sport; /* source port */
     uint16_t uh_dport; /* destination port */
@@ -108,11 +118,34 @@ struct ip6_header {
     struct in6_address ip6_dst;    /* destination address */
 };
 
+typedef struct ip6_pseudo_header {
+    struct in6_address ip6_src;
+    struct in6_address ip6_dst;
+    uint32_t           len;
+    uint8_t            zero[3];
+    uint8_t            next_hdr;
+} ip6_pseudo_header;
+
 struct ip6_ext_hdr {
     uint8_t        ip6r_nxt;   /* next header */
     uint8_t        ip6r_len;   /* length in units of 8 octets */
 };
 
+struct ip6_ext_hdr_routing {
+    uint8_t     nxt;
+    uint8_t     len;
+    uint8_t     rtype;
+    uint8_t     segleft;
+    uint8_t     rsvd[4];
+};
+
+struct ip6_option_hdr {
+#define IP6_OPT_PAD1   (0x00)
+#define IP6_OPT_HOME   (0xC9)
+    uint8_t type;
+    uint8_t len;
+};
+
 struct udp_hdr {
   uint16_t uh_sport;           /* source port */
   uint16_t uh_dport;           /* destination port */
@@ -161,19 +194,22 @@ struct tcp_hdr {
 #define PKT_GET_IP_HDR(p)         \
     ((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
 #define IP_HDR_GET_LEN(p)         \
-    ((((struct ip_header *)p)->ip_ver_len & 0x0F) << 2)
+    ((((struct ip_header *)(p))->ip_ver_len & 0x0F) << 2)
 #define PKT_GET_IP_HDR_LEN(p)     \
     (IP_HDR_GET_LEN(PKT_GET_IP_HDR(p)))
 #define PKT_GET_IP6_HDR(p)        \
     ((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
 #define IP_HEADER_VERSION(ip)     \
-    ((ip->ip_ver_len >> 4)&0xf)
+    (((ip)->ip_ver_len >> 4) & 0xf)
+#define IP4_IS_FRAGMENT(ip) \
+    ((be16_to_cpu((ip)->ip_off) & (IP_OFFMASK | IP_MF)) != 0)
 
 #define ETH_P_IP                  (0x0800)      /* Internet Protocol packet  */
 #define ETH_P_ARP                 (0x0806)      /* Address Resolution packet */
 #define ETH_P_IPV6                (0x86dd)
 #define ETH_P_VLAN                (0x8100)
 #define ETH_P_DVLAN               (0x88a8)
+#define ETH_P_UNKNOWN             (0xffff)
 #define VLAN_VID_MASK             0x0fff
 #define IP_HEADER_VERSION_4       (4)
 #define IP_HEADER_VERSION_6       (6)
@@ -258,7 +294,7 @@ eth_get_l2_hdr_length(const void *p)
     case ETH_P_VLAN:
         return sizeof(struct eth_header) + sizeof(struct vlan_header);
     case ETH_P_DVLAN:
-        if (hvlan->h_proto == ETH_P_VLAN) {
+        if (be16_to_cpu(hvlan->h_proto) == ETH_P_VLAN) {
             return sizeof(struct eth_header) + 2 * sizeof(struct vlan_header);
         } else {
             return sizeof(struct eth_header) + sizeof(struct vlan_header);
@@ -268,6 +304,19 @@ eth_get_l2_hdr_length(const void *p)
     }
 }
 
+static inline uint32_t
+eth_get_l2_hdr_length_iov(const struct iovec *iov, int iovcnt)
+{
+    uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
+    size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p));
+
+    if (copied < ARRAY_SIZE(p)) {
+        return copied;
+    }
+
+    return eth_get_l2_hdr_length(p);
+}
+
 static inline uint16_t
 eth_get_pkt_tci(const void *p)
 {
@@ -282,51 +331,67 @@ eth_get_pkt_tci(const void *p)
     }
 }
 
-static inline bool
-eth_strip_vlan(const void *p, uint8_t *new_ehdr_buf,
-               uint16_t *payload_offset, uint16_t *tci)
-{
-    uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
-    struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
-    struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf;
+bool
+eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
+               uint8_t *new_ehdr_buf,
+               uint16_t *payload_offset, uint16_t *tci);
 
-    switch (proto) {
-    case ETH_P_VLAN:
-    case ETH_P_DVLAN:
-        memcpy(new_ehdr->h_source, PKT_GET_ETH_HDR(p)->h_source, ETH_ALEN);
-        memcpy(new_ehdr->h_dest, PKT_GET_ETH_HDR(p)->h_dest, ETH_ALEN);
-        new_ehdr->h_proto = hvlan->h_proto;
-        *tci = be16_to_cpu(hvlan->h_tci);
-        *payload_offset =
-            sizeof(struct eth_header) + sizeof(struct vlan_header);
-        if (be16_to_cpu(new_ehdr->h_proto) == ETH_P_VLAN) {
-            memcpy(PKT_GET_VLAN_HDR(new_ehdr),
-                   PKT_GET_DVLAN_HDR(p),
-                   sizeof(struct vlan_header));
-            *payload_offset += sizeof(struct vlan_header);
-        }
-        return true;
-    default:
-        return false;
-    }
-}
+bool
+eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
+                  uint16_t vet, uint8_t *new_ehdr_buf,
+                  uint16_t *payload_offset, uint16_t *tci);
 
-static inline uint16_t
-eth_get_l3_proto(const void *l2hdr, size_t l2hdr_len)
+uint16_t
+eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len);
+
+void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag,
+    uint16_t vlan_ethtype, bool *is_new);
+
+static inline void
+eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag,
+    bool *is_new)
 {
-    uint8_t *proto_ptr = (uint8_t *) l2hdr + l2hdr_len - sizeof(uint16_t);
-    return be16_to_cpup((uint16_t *)proto_ptr);
+    eth_setup_vlan_headers_ex(ehdr, vlan_tag, ETH_P_VLAN, is_new);
 }
 
-void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag,
-    bool *is_new);
 
 uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto);
 
-void eth_get_protocols(const uint8_t *headers,
-                       uint32_t hdr_length,
+typedef struct eth_ip6_hdr_info_st {
+    uint8_t l4proto;
+    size_t  full_hdr_len;
+    struct  ip6_header ip6_hdr;
+    bool    has_ext_hdrs;
+    bool    rss_ex_src_valid;
+    struct  in6_address rss_ex_src;
+    bool    rss_ex_dst_valid;
+    struct  in6_address rss_ex_dst;
+    bool    fragment;
+} eth_ip6_hdr_info;
+
+typedef struct eth_ip4_hdr_info_st {
+    struct ip_header ip4_hdr;
+    bool   fragment;
+} eth_ip4_hdr_info;
+
+typedef struct eth_l4_hdr_info_st {
+    union {
+        struct tcp_header tcp;
+        struct udp_header udp;
+    } hdr;
+
+    bool has_tcp_data;
+} eth_l4_hdr_info;
+
+void eth_get_protocols(const struct iovec *iov, int iovcnt,
                        bool *isip4, bool *isip6,
-                       bool *isudp, bool *istcp);
+                       bool *isudp, bool *istcp,
+                       size_t *l3hdr_off,
+                       size_t *l4hdr_off,
+                       size_t *l5hdr_off,
+                       eth_ip6_hdr_info *ip6hdr_info,
+                       eth_ip4_hdr_info *ip4hdr_info,
+                       eth_l4_hdr_info  *l4hdr_info);
 
 void eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len,
                                  void *l3hdr, size_t l3hdr_len,
@@ -337,11 +402,18 @@ void
 eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len);
 
 uint32_t
-eth_calc_pseudo_hdr_csum(struct ip_header *iphdr, uint16_t csl);
+eth_calc_ip4_pseudo_hdr_csum(struct ip_header *iphdr,
+                             uint16_t csl,
+                             uint32_t *cso);
+
+uint32_t
+eth_calc_ip6_pseudo_hdr_csum(struct ip6_header *iphdr,
+                             uint16_t csl,
+                             uint8_t l4_proto,
+                             uint32_t *cso);
 
 bool
-eth_parse_ipv6_hdr(struct iovec *pkt, int pkt_frags,
-                   size_t ip6hdr_off, uint8_t *l4proto,
-                   size_t *full_hdr_len);
+eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags,
+                   size_t ip6hdr_off, eth_ip6_hdr_info *info);
 
 #endif
diff --git a/include/net/net.h b/include/net/net.h
index 73e4c466e2..a69e382ba7 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -9,6 +9,11 @@
 #include "migration/vmstate.h"
 #include "qapi-types.h"
 
+#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
+#define MAC_ARG(x) ((uint8_t *)(x))[0], ((uint8_t *)(x))[1], \
+                   ((uint8_t *)(x))[2], ((uint8_t *)(x))[3], \
+                   ((uint8_t *)(x))[4], ((uint8_t *)(x))[5]
+
 #define MAX_QUEUE_NUM 1024
 
 /* Maximum GSO packet size (64k) plus plenty of room for
@@ -57,6 +62,8 @@ typedef void (SetOffload)(NetClientState *, int, int, int, int, int);
 typedef void (SetVnetHdrLen)(NetClientState *, int);
 typedef int (SetVnetLE)(NetClientState *, bool);
 typedef int (SetVnetBE)(NetClientState *, bool);
+typedef struct SocketReadState SocketReadState;
+typedef void (SocketReadStateFinalize)(SocketReadState *rs);
 
 typedef struct NetClientInfo {
     NetClientOptionsKind type;
@@ -102,6 +109,15 @@ typedef struct NICState {
     bool peer_deleted;
 } NICState;
 
+struct SocketReadState {
+    int state; /* 0 = getting length, 1 = getting data */
+    uint32_t index;
+    uint32_t packet_len;
+    uint8_t buf[NET_BUFSIZE];
+    SocketReadStateFinalize *finalize;
+};
+
+int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size);
 char *qemu_mac_strdup_printf(const uint8_t *macaddr);
 NetClientState *qemu_find_netdev(const char *id);
 int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
@@ -160,6 +176,8 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
 
 void print_net_client(Monitor *mon, NetClientState *nc);
 void hmp_info_network(Monitor *mon, const QDict *qdict);
+void net_socket_rs_init(SocketReadState *rs,
+                        SocketReadStateFinalize *finalize);
 
 /* NIC info */
 
@@ -178,7 +196,6 @@ struct NICInfo {
 
 extern int nb_nics;
 extern NICInfo nd_table[MAX_NICS];
-extern int default_net;
 extern const char *host_net_devices[];
 
 /* from net.c */