diff mbox series

[RFC,5/6] virtio-net: steering mode: Implement rss support

Message ID 20180830142708.14311-6-sameeh@daynix.com
State New
Headers show
Series Virtio-net: Support RSS | expand

Commit Message

Sameeh Jubran Aug. 30, 2018, 2:27 p.m. UTC
From: Sameeh Jubran <sjubran@redhat.com>

Signed-off-by: Sameeh Jubran <sjubran@redhat.com>
---
 hw/net/virtio-net.c | 122 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 105 insertions(+), 17 deletions(-)

Comments

Jason Wang Sept. 3, 2018, 3:48 a.m. UTC | #1
On 2018年08月30日 22:27, Sameeh Jubran wrote:
> From: Sameeh Jubran <sjubran@redhat.com>
>
> Signed-off-by: Sameeh Jubran <sjubran@redhat.com>
> ---
>   hw/net/virtio-net.c | 122 ++++++++++++++++++++++++++++++++++++++++++++--------
>   1 file changed, 105 insertions(+), 17 deletions(-)
>
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index e7c4ce6f66..4a52a6a1d0 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -972,41 +972,129 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
>       return VIRTIO_NET_OK;
>   }
>   
> -static int virtio_net_ctrl_steering_mode(VirtIONet *n, uint8_t cmd,
> +
> +static int virtio_net_ctrl_sm_rss(VirtIONet *n, uint32_t cmd,
>                                   struct iovec *iov, unsigned int iov_cnt,
>                                   struct iovec *iov_in, unsigned int iov_cnt_in,
> -        size_t *size_in)
> +                                size_t *size_in)
> +{
> +    size_t s;
> +    uint32_t supported_hash_function = 0;
> +
> +    switch (cmd) {
> +    case VIRTIO_NET_SM_CTRL_RSS_GET_SUPPORTED_FUNCTIONS:
> +        supported_hash_function |= RSS_HASH_FUNCTION_TOEPLITZ;
> +        if (!size_in) {
> +            return VIRTIO_NET_ERR;
> +        }
> +        s = iov_from_buf(iov_in, iov_cnt_in, 0,
> +        &supported_hash_function,
> +        supported_hash_function);

Indentation looks wrong.

> +        if (s != sizeof(n->supported_modes) ||
> +        !size_in) {
> +            return VIRTIO_NET_ERR;
> +        }
> +        *size_in = s;
> +        break;
> +    case VIRTIO_NET_SM_CTRL_RSS_SET:
> +        if (!n->rss_conf) {
> +            n->rss_conf = g_malloc0(
> +                    sizeof(struct virtio_net_rss_conf));
> +        } else if (iov == NULL || iov_cnt == 0) {
> +            g_free(n->rss_conf->ptrs.hash_key);
> +            g_free(n->rss_conf->ptrs.indirection_table);
> +            g_free(n->rss_conf);
> +            return VIRTIO_NET_OK;
> +        }
> +        s = iov_to_buf(iov, iov_cnt, 0, n->rss_conf,
> +                sizeof(struct virtio_net_rss_conf) -
> +                sizeof(struct virtio_net_rss_conf_ptrs));
> +
> +        if (s != sizeof(struct virtio_net_rss_conf) -
> +                sizeof(struct virtio_net_rss_conf_ptrs)) {
> +            return VIRTIO_NET_ERR;
> +        }
> +        n->rss_conf->ptrs.hash_key = g_malloc0(sizeof(uint8_t) *
> +                n->rss_conf->hash_key_length);

What happens if n->rss_conf != 0 && iov != NULL? Looks like a guest 
trigger-able OOM?

Btw e.g "conf_ptrs" sounds misleading, why not just embed hash key and 
indirection table pointers directly in rss_conf structure itself?

> +        s = iov_to_buf(iov, iov_cnt, 0, n->rss_conf->ptrs.hash_key,
> +                sizeof(uint8_t) * n->rss_conf->hash_key_length);
> +        if (s != sizeof(uint8_t) * n->rss_conf->hash_key_length) {
> +            g_free(n->rss_conf->ptrs.hash_key);
> +            return VIRTIO_NET_ERR;
> +        }
> +        n->rss_conf->ptrs.indirection_table
> +            = g_malloc0(sizeof(uint32_t) *
> +                    n->rss_conf->indirection_table_length);
> +        s = iov_to_buf(iov, iov_cnt, 0,
> +                n->rss_conf->ptrs.indirection_table, sizeof(uint32_t) *
> +                n->rss_conf->indirection_table_length);
> +        if (s != sizeof(uint32_t) *
> +                n->rss_conf->indirection_table_length) {
> +            g_free(n->rss_conf->ptrs.hash_key);
> +            g_free(n->rss_conf->ptrs.indirection_table);
> +            return VIRTIO_NET_ERR;
> +        }
> +        /* do bpf magic */
> +        break;
> +    default:
> +        return VIRTIO_NET_ERR;
> +    }
> +
> +    return VIRTIO_NET_OK;
> +}
> +
> +static int virtio_net_ctrl_steering_mode(VirtIONet *n, uint8_t cmd,
> +                                struct iovec *iov, unsigned int iov_cnt,
> +                                struct iovec *iov_in, unsigned int iov_in_cnt,
> +                                size_t *size_in)
>   {
>       size_t s;
>       struct virtio_net_steering_mode sm;
> +    int status = 0;
> +    size_t size_in_cmd = 0;
>   
>       switch (cmd) {
>       case VIRTIO_NET_CTRL_SM_GET_SUPPORTED_MODES:
>           if (!size_in) {
>               return VIRTIO_NET_ERR;
>           }
> -                  s = iov_from_buf(iov_in, iov_cnt_in, 0,
> -          &n->supported_modes, sizeof(n->supported_modes));
> +        n->supported_modes.steering_modes |= STEERING_MODE_RSS |
> +            STEERING_MODE_AUTO;

We should have a property for RSS instead of hard coding it here.

Thanks

> +        s = iov_from_buf(iov_in, iov_in_cnt, 0,
> +        &n->supported_modes,
> +        sizeof(n->supported_modes));
>           if (s != sizeof(n->supported_modes) ||
> -          !size_in) {
> +        !size_in) {
>               return VIRTIO_NET_ERR;
>           }
> -                  *size_in = s;
> -      break;
> +        *size_in = s;
> +         break;
>       case VIRTIO_NET_CTRL_SM_CONTROL:
> -        s = iov_to_buf(iov, iov_cnt, 0, &sm, sizeof(sm) -
> -                sizeof(union command_data));
> -        if (s != sizeof(sm) - sizeof(union command_data)) {
> +        s = iov_to_buf(iov, iov_cnt, 0, &sm, sizeof(sm));
> +        if (s != sizeof(sm)) {
> +            return VIRTIO_NET_ERR;
> +        }
> +        iov_discard_front(&iov, &iov_cnt, sizeof(sm));
> +        /* TODO handle the case where we change mode, call the old */
> +        /* mode function with null ptrs  should do the trick of */
> +        /* freeing any resources */
> +        switch (sm.steering_mode) {
> +        case STEERING_MODE_AUTO:
> +                    break;
> +        case STEERING_MODE_RSS:
> +            status = virtio_net_ctrl_sm_rss(n, sm.command,
> +                   iov, iov_cnt, iov_in, iov_in_cnt,
> +                   &size_in_cmd);
> +            if (status == VIRTIO_NET_OK && size_in_cmd > 0) {
> +                *size_in += size_in_cmd;
> +            }
> +            break;
> +        default:
>               return VIRTIO_NET_ERR;
>           }
> -        /* switch (cmd)
> -             {
> -                dafault:
> -                return VIRTIO_NET_ERR;
> -         } */
> -      break;
> +        break;
>       default:
> -                return VIRTIO_NET_ERR;
> +        return VIRTIO_NET_ERR;
>       }
>   
>       return VIRTIO_NET_OK;
Sameeh Jubran Sept. 3, 2018, 11:45 a.m. UTC | #2
On Mon, Sep 3, 2018 at 6:48 AM, Jason Wang <jasowang@redhat.com> wrote:
>
>
> On 2018年08月30日 22:27, Sameeh Jubran wrote:
>>
>> From: Sameeh Jubran <sjubran@redhat.com>
>>
>> Signed-off-by: Sameeh Jubran <sjubran@redhat.com>
>> ---
>>   hw/net/virtio-net.c | 122
>> ++++++++++++++++++++++++++++++++++++++++++++--------
>>   1 file changed, 105 insertions(+), 17 deletions(-)
>>
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index e7c4ce6f66..4a52a6a1d0 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -972,41 +972,129 @@ static int virtio_net_handle_mq(VirtIONet *n,
>> uint8_t cmd,
>>       return VIRTIO_NET_OK;
>>   }
>>   -static int virtio_net_ctrl_steering_mode(VirtIONet *n, uint8_t cmd,
>> +
>> +static int virtio_net_ctrl_sm_rss(VirtIONet *n, uint32_t cmd,
>>                                   struct iovec *iov, unsigned int iov_cnt,
>>                                   struct iovec *iov_in, unsigned int
>> iov_cnt_in,
>> -        size_t *size_in)
>> +                                size_t *size_in)
>> +{
>> +    size_t s;
>> +    uint32_t supported_hash_function = 0;
>> +
>> +    switch (cmd) {
>> +    case VIRTIO_NET_SM_CTRL_RSS_GET_SUPPORTED_FUNCTIONS:
>> +        supported_hash_function |= RSS_HASH_FUNCTION_TOEPLITZ;
>> +        if (!size_in) {
>> +            return VIRTIO_NET_ERR;
>> +        }
>> +        s = iov_from_buf(iov_in, iov_cnt_in, 0,
>> +        &supported_hash_function,
>> +        supported_hash_function);
>
>
> Indentation looks wrong.
>
>
>> +        if (s != sizeof(n->supported_modes) ||
>> +        !size_in) {
>> +            return VIRTIO_NET_ERR;
>> +        }
>> +        *size_in = s;
>> +        break;
>> +    case VIRTIO_NET_SM_CTRL_RSS_SET:
>> +        if (!n->rss_conf) {
>> +            n->rss_conf = g_malloc0(
>> +                    sizeof(struct virtio_net_rss_conf));
>> +        } else if (iov == NULL || iov_cnt == 0) {
>> +            g_free(n->rss_conf->ptrs.hash_key);
>> +            g_free(n->rss_conf->ptrs.indirection_table);
>> +            g_free(n->rss_conf);
>> +            return VIRTIO_NET_OK;
>> +        }
>> +        s = iov_to_buf(iov, iov_cnt, 0, n->rss_conf,
>> +                sizeof(struct virtio_net_rss_conf) -
>> +                sizeof(struct virtio_net_rss_conf_ptrs));
>> +
>> +        if (s != sizeof(struct virtio_net_rss_conf) -
>> +                sizeof(struct virtio_net_rss_conf_ptrs)) {
>> +            return VIRTIO_NET_ERR;
>> +        }
>> +        n->rss_conf->ptrs.hash_key = g_malloc0(sizeof(uint8_t) *
>> +                n->rss_conf->hash_key_length);
>
>
> What happens if n->rss_conf != 0 && iov != NULL? Looks like a guest
> trigger-able OOM?
>
> Btw e.g "conf_ptrs" sounds misleading, why not just embed hash key and
> indirection table pointers directly in rss_conf structure itself?
It was neater to do it like this so I can use:
sizeof(struct virtio_net_rss_conf) - sizeof(struct virtio_net_rss_conf_ptrs)
when reading from the iov, but yeah it not a big deal and I can put
the pointers there as well
>
>
>> +        s = iov_to_buf(iov, iov_cnt, 0, n->rss_conf->ptrs.hash_key,
>> +                sizeof(uint8_t) * n->rss_conf->hash_key_length);
>> +        if (s != sizeof(uint8_t) * n->rss_conf->hash_key_length) {
>> +            g_free(n->rss_conf->ptrs.hash_key);
>> +            return VIRTIO_NET_ERR;
>> +        }
>> +        n->rss_conf->ptrs.indirection_table
>> +            = g_malloc0(sizeof(uint32_t) *
>> +                    n->rss_conf->indirection_table_length);
>> +        s = iov_to_buf(iov, iov_cnt, 0,
>> +                n->rss_conf->ptrs.indirection_table, sizeof(uint32_t) *
>> +                n->rss_conf->indirection_table_length);
>> +        if (s != sizeof(uint32_t) *
>> +                n->rss_conf->indirection_table_length) {
>> +            g_free(n->rss_conf->ptrs.hash_key);
>> +            g_free(n->rss_conf->ptrs.indirection_table);
>> +            return VIRTIO_NET_ERR;
>> +        }
>> +        /* do bpf magic */
>> +        break;
>> +    default:
>> +        return VIRTIO_NET_ERR;
>> +    }
>> +
>> +    return VIRTIO_NET_OK;
>> +}
>> +
>> +static int virtio_net_ctrl_steering_mode(VirtIONet *n, uint8_t cmd,
>> +                                struct iovec *iov, unsigned int iov_cnt,
>> +                                struct iovec *iov_in, unsigned int
>> iov_in_cnt,
>> +                                size_t *size_in)
>>   {
>>       size_t s;
>>       struct virtio_net_steering_mode sm;
>> +    int status = 0;
>> +    size_t size_in_cmd = 0;
>>         switch (cmd) {
>>       case VIRTIO_NET_CTRL_SM_GET_SUPPORTED_MODES:
>>           if (!size_in) {
>>               return VIRTIO_NET_ERR;
>>           }
>> -                  s = iov_from_buf(iov_in, iov_cnt_in, 0,
>> -          &n->supported_modes, sizeof(n->supported_modes));
>> +        n->supported_modes.steering_modes |= STEERING_MODE_RSS |
>> +            STEERING_MODE_AUTO;
>
>
> We should have a property for RSS instead of hard coding it here.
Agree
>
> Thanks
>
>
>> +        s = iov_from_buf(iov_in, iov_in_cnt, 0,
>> +        &n->supported_modes,
>> +        sizeof(n->supported_modes));
>>           if (s != sizeof(n->supported_modes) ||
>> -          !size_in) {
>> +        !size_in) {
>>               return VIRTIO_NET_ERR;
>>           }
>> -                  *size_in = s;
>> -      break;
>> +        *size_in = s;
>> +         break;
>>       case VIRTIO_NET_CTRL_SM_CONTROL:
>> -        s = iov_to_buf(iov, iov_cnt, 0, &sm, sizeof(sm) -
>> -                sizeof(union command_data));
>> -        if (s != sizeof(sm) - sizeof(union command_data)) {
>> +        s = iov_to_buf(iov, iov_cnt, 0, &sm, sizeof(sm));
>> +        if (s != sizeof(sm)) {
>> +            return VIRTIO_NET_ERR;
>> +        }
>> +        iov_discard_front(&iov, &iov_cnt, sizeof(sm));
>> +        /* TODO handle the case where we change mode, call the old */
>> +        /* mode function with null ptrs  should do the trick of */
>> +        /* freeing any resources */
>> +        switch (sm.steering_mode) {
>> +        case STEERING_MODE_AUTO:
>> +                    break;
>> +        case STEERING_MODE_RSS:
>> +            status = virtio_net_ctrl_sm_rss(n, sm.command,
>> +                   iov, iov_cnt, iov_in, iov_in_cnt,
>> +                   &size_in_cmd);
>> +            if (status == VIRTIO_NET_OK && size_in_cmd > 0) {
>> +                *size_in += size_in_cmd;
>> +            }
>> +            break;
>> +        default:
>>               return VIRTIO_NET_ERR;
>>           }
>> -        /* switch (cmd)
>> -             {
>> -                dafault:
>> -                return VIRTIO_NET_ERR;
>> -         } */
>> -      break;
>> +        break;
>>       default:
>> -                return VIRTIO_NET_ERR;
>> +        return VIRTIO_NET_ERR;
>>       }
>>         return VIRTIO_NET_OK;
>
>
diff mbox series

Patch

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index e7c4ce6f66..4a52a6a1d0 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -972,41 +972,129 @@  static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
     return VIRTIO_NET_OK;
 }
 
-static int virtio_net_ctrl_steering_mode(VirtIONet *n, uint8_t cmd,
+
+static int virtio_net_ctrl_sm_rss(VirtIONet *n, uint32_t cmd,
                                 struct iovec *iov, unsigned int iov_cnt,
                                 struct iovec *iov_in, unsigned int iov_cnt_in,
-        size_t *size_in)
+                                size_t *size_in)
+{
+    size_t s;
+    uint32_t supported_hash_function = 0;
+
+    switch (cmd) {
+    case VIRTIO_NET_SM_CTRL_RSS_GET_SUPPORTED_FUNCTIONS:
+        supported_hash_function |= RSS_HASH_FUNCTION_TOEPLITZ;
+        if (!size_in) {
+            return VIRTIO_NET_ERR;
+        }
+        s = iov_from_buf(iov_in, iov_cnt_in, 0,
+        &supported_hash_function,
+        supported_hash_function);
+        if (s != sizeof(n->supported_modes) ||
+        !size_in) {
+            return VIRTIO_NET_ERR;
+        }
+        *size_in = s;
+        break;
+    case VIRTIO_NET_SM_CTRL_RSS_SET:
+        if (!n->rss_conf) {
+            n->rss_conf = g_malloc0(
+                    sizeof(struct virtio_net_rss_conf));
+        } else if (iov == NULL || iov_cnt == 0) {
+            g_free(n->rss_conf->ptrs.hash_key);
+            g_free(n->rss_conf->ptrs.indirection_table);
+            g_free(n->rss_conf);
+            return VIRTIO_NET_OK;
+        }
+        s = iov_to_buf(iov, iov_cnt, 0, n->rss_conf,
+                sizeof(struct virtio_net_rss_conf) -
+                sizeof(struct virtio_net_rss_conf_ptrs));
+
+        if (s != sizeof(struct virtio_net_rss_conf) -
+                sizeof(struct virtio_net_rss_conf_ptrs)) {
+            return VIRTIO_NET_ERR;
+        }
+        n->rss_conf->ptrs.hash_key = g_malloc0(sizeof(uint8_t) *
+                n->rss_conf->hash_key_length);
+        s = iov_to_buf(iov, iov_cnt, 0, n->rss_conf->ptrs.hash_key,
+                sizeof(uint8_t) * n->rss_conf->hash_key_length);
+        if (s != sizeof(uint8_t) * n->rss_conf->hash_key_length) {
+            g_free(n->rss_conf->ptrs.hash_key);
+            return VIRTIO_NET_ERR;
+        }
+        n->rss_conf->ptrs.indirection_table
+            = g_malloc0(sizeof(uint32_t) *
+                    n->rss_conf->indirection_table_length);
+        s = iov_to_buf(iov, iov_cnt, 0,
+                n->rss_conf->ptrs.indirection_table, sizeof(uint32_t) *
+                n->rss_conf->indirection_table_length);
+        if (s != sizeof(uint32_t) *
+                n->rss_conf->indirection_table_length) {
+            g_free(n->rss_conf->ptrs.hash_key);
+            g_free(n->rss_conf->ptrs.indirection_table);
+            return VIRTIO_NET_ERR;
+        }
+        /* do bpf magic */
+        break;
+    default:
+        return VIRTIO_NET_ERR;
+    }
+
+    return VIRTIO_NET_OK;
+}
+
+static int virtio_net_ctrl_steering_mode(VirtIONet *n, uint8_t cmd,
+                                struct iovec *iov, unsigned int iov_cnt,
+                                struct iovec *iov_in, unsigned int iov_in_cnt,
+                                size_t *size_in)
 {
     size_t s;
     struct virtio_net_steering_mode sm;
+    int status = 0;
+    size_t size_in_cmd = 0;
 
     switch (cmd) {
     case VIRTIO_NET_CTRL_SM_GET_SUPPORTED_MODES:
         if (!size_in) {
             return VIRTIO_NET_ERR;
         }
-                  s = iov_from_buf(iov_in, iov_cnt_in, 0,
-          &n->supported_modes, sizeof(n->supported_modes));
+        n->supported_modes.steering_modes |= STEERING_MODE_RSS |
+            STEERING_MODE_AUTO;
+        s = iov_from_buf(iov_in, iov_in_cnt, 0,
+        &n->supported_modes,
+        sizeof(n->supported_modes));
         if (s != sizeof(n->supported_modes) ||
-          !size_in) {
+        !size_in) {
             return VIRTIO_NET_ERR;
         }
-                  *size_in = s;
-      break;
+        *size_in = s;
+         break;
     case VIRTIO_NET_CTRL_SM_CONTROL:
-        s = iov_to_buf(iov, iov_cnt, 0, &sm, sizeof(sm) -
-                sizeof(union command_data));
-        if (s != sizeof(sm) - sizeof(union command_data)) {
+        s = iov_to_buf(iov, iov_cnt, 0, &sm, sizeof(sm));
+        if (s != sizeof(sm)) {
+            return VIRTIO_NET_ERR;
+        }
+        iov_discard_front(&iov, &iov_cnt, sizeof(sm));
+        /* TODO handle the case where we change mode, call the old */
+        /* mode function with null ptrs  should do the trick of */
+        /* freeing any resources */
+        switch (sm.steering_mode) {
+        case STEERING_MODE_AUTO:
+                    break;
+        case STEERING_MODE_RSS:
+            status = virtio_net_ctrl_sm_rss(n, sm.command,
+                   iov, iov_cnt, iov_in, iov_in_cnt,
+                   &size_in_cmd);
+            if (status == VIRTIO_NET_OK && size_in_cmd > 0) {
+                *size_in += size_in_cmd;
+            }
+            break;
+        default:
             return VIRTIO_NET_ERR;
         }
-        /* switch (cmd)
-             {
-                dafault:
-                return VIRTIO_NET_ERR;
-         } */
-      break;
+        break;
     default:
-                return VIRTIO_NET_ERR;
+        return VIRTIO_NET_ERR;
     }
 
     return VIRTIO_NET_OK;