diff mbox

[ovs-dev,v3,10/11] netdev: Add reconfigure request mechanism.

Message ID 1458081003-82542-11-git-send-email-diproiettod@vmware.com
State Superseded, archived
Headers show

Commit Message

Daniele Di Proietto March 15, 2016, 10:30 p.m. UTC
A netdev provider, especially a PMD provider (like netdev DPDK) might
not be able to change some of its parameters (such as MTU, or number of
queues) without stopping everything and restarting.

This commit introduces a mechanism that allows a netdev provider to
request a restart (netdev_request_reconfigure()).  The upper layer can
be notified via netdev_wait_reconf_required() and
netdev_is_reconf_required().  After closing all the rxqs the upper layer
can finally call netdev_reconfigure(), to make sure that the new
configuration is in place.

This will be used by next commit to reconfigure rx and tx queues in
netdev-dpdk.

Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
---
 lib/netdev-bsd.c      |  1 +
 lib/netdev-dpdk.c     |  1 +
 lib/netdev-dummy.c    |  1 +
 lib/netdev-linux.c    |  1 +
 lib/netdev-provider.h | 27 ++++++++++++++++++++++++++-
 lib/netdev-vport.c    |  1 +
 lib/netdev.c          | 38 ++++++++++++++++++++++++++++++++++++++
 lib/netdev.h          |  4 ++++
 8 files changed, 73 insertions(+), 1 deletion(-)

Comments

Ilya Maximets March 16, 2016, 1:12 p.m. UTC | #1
On 16.03.2016 01:30, Daniele Di Proietto wrote:
> A netdev provider, especially a PMD provider (like netdev DPDK) might
> not be able to change some of its parameters (such as MTU, or number of
> queues) without stopping everything and restarting.
> 
> This commit introduces a mechanism that allows a netdev provider to
> request a restart (netdev_request_reconfigure()).  The upper layer can
> be notified via netdev_wait_reconf_required() and
> netdev_is_reconf_required().  After closing all the rxqs the upper layer
> can finally call netdev_reconfigure(), to make sure that the new
> configuration is in place.
> 
> This will be used by next commit to reconfigure rx and tx queues in
> netdev-dpdk.
> 
> Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
> ---
>  lib/netdev-bsd.c      |  1 +
>  lib/netdev-dpdk.c     |  1 +
>  lib/netdev-dummy.c    |  1 +
>  lib/netdev-linux.c    |  1 +
>  lib/netdev-provider.h | 27 ++++++++++++++++++++++++++-
>  lib/netdev-vport.c    |  1 +
>  lib/netdev.c          | 38 ++++++++++++++++++++++++++++++++++++++
>  lib/netdev.h          |  4 ++++
>  8 files changed, 73 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
> index edf04bf..724e6d4 100644
> --- a/lib/netdev-bsd.c
> +++ b/lib/netdev-bsd.c
> @@ -1602,6 +1602,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
>      netdev_bsd_arp_lookup, /* arp_lookup */          \
>                                                       \
>      netdev_bsd_update_flags,                         \
> +    NULL, /* reconfigure */                          \
>                                                       \
>      netdev_bsd_rxq_alloc,                            \
>      netdev_bsd_rxq_construct,                        \
> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
> index f402354..b5867e8 100644
> --- a/lib/netdev-dpdk.c
> +++ b/lib/netdev-dpdk.c
> @@ -2696,6 +2696,7 @@ static const struct dpdk_qos_ops egress_policer_ops = {
>      NULL,                       /* arp_lookup */              \
>                                                                \
>      netdev_dpdk_update_flags,                                 \
> +    NULL,                       /* reconfigure */             \
>                                                                \
>      netdev_dpdk_rxq_alloc,                                    \
>      netdev_dpdk_rxq_construct,                                \
> diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
> index ccd4a0a..d7524eb 100644
> --- a/lib/netdev-dummy.c
> +++ b/lib/netdev-dummy.c
> @@ -1251,6 +1251,7 @@ static const struct netdev_class dummy_class = {
>      NULL,                       /* arp_lookup */
>  
>      netdev_dummy_update_flags,
> +    NULL,                       /* reconfigure */
>  
>      netdev_dummy_rxq_alloc,
>      netdev_dummy_rxq_construct,
> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
> index 570677e..f9ad126 100644
> --- a/lib/netdev-linux.c
> +++ b/lib/netdev-linux.c
> @@ -2897,6 +2897,7 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
>      netdev_linux_arp_lookup,                                    \
>                                                                  \
>      netdev_linux_update_flags,                                  \
> +    NULL,                       /* reconfigure */               \
>                                                                  \
>      netdev_linux_rxq_alloc,                                     \
>      netdev_linux_rxq_construct,                                 \
> diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
> index 1952a02..0317910 100644
> --- a/lib/netdev-provider.h
> +++ b/lib/netdev-provider.h
> @@ -52,6 +52,16 @@ struct netdev {
>       * 'netdev''s flags, features, ethernet address, or carrier changes. */
>      uint64_t change_seq;
>  
> +    /* A netdev provider might be unable to change some of the device's
> +     * parameter (n_rxq, mtu) when the device is in use.  In this case
> +     * the provider can notify the upper layer by calling
> +     * netdev_request_reconfigure().  The upper layer will react by stopping
> +     * the operations on the device and calling netdev_reconfigure() to allow
> +     * the configuration changes.  'last_reconfigure_seq' remembers the value
> +     * of 'reconfigure_seq' when the last reconfiguration happened. */
> +    struct seq *reconfigure_seq;
> +    uint64_t last_reconfigure_seq;
> +
>      /* The core netdev code initializes these at netdev construction and only
>       * provide read-only access to its client.  Netdev implementations may
>       * modify them. */
> @@ -64,7 +74,7 @@ struct netdev {
>      struct ovs_list saved_flags_list; /* Contains "struct netdev_saved_flags". */
>  };
>  
> -static void
> +static inline void
>  netdev_change_seq_changed(const struct netdev *netdev_)
>  {
>      struct netdev *netdev = CONST_CAST(struct netdev *, netdev_);
> @@ -75,6 +85,12 @@ netdev_change_seq_changed(const struct netdev *netdev_)
>      }
>  }
>  
> +static inline void
> +netdev_request_reconfigure(struct netdev *netdev)
> +{
> +    seq_change(netdev->reconfigure_seq);
> +}
> +
>  const char *netdev_get_type(const struct netdev *);
>  const struct netdev_class *netdev_get_class(const struct netdev *);
>  const char *netdev_get_name(const struct netdev *);
> @@ -699,6 +715,15 @@ struct netdev_class {
>      int (*update_flags)(struct netdev *netdev, enum netdev_flags off,
>                          enum netdev_flags on, enum netdev_flags *old_flags);
>  
> +    /* If the provider called netdev_request_reconfigure(), the upper layer
> +     * will eventually call this.  The provider can update the device
> +     * configuration knowing that the upper layer will not call rxq_recv() or
> +     * send() until this function returns.
> +     *
> +     * On error, the configuration is indeterminant and the device cannot be
> +     * used to send and receive packets until a successful configuration is
> +     * applied. */
> +    int (*reconfigure)(struct netdev *netdev);
>  /* ## -------------------- ## */
>  /* ## netdev_rxq Functions ## */
>  /* ## -------------------- ## */
> diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
> index df6d8cf..d055f10 100644
> --- a/lib/netdev-vport.c
> +++ b/lib/netdev-vport.c
> @@ -1537,6 +1537,7 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
>      NULL,                       /* arp_lookup */            \
>                                                              \
>      netdev_vport_update_flags,                              \
> +    NULL,                       /* reconfigure */           \
>                                                              \
>      NULL,                   /* rx_alloc */                  \
>      NULL,                   /* rx_construct */              \
> diff --git a/lib/netdev.c b/lib/netdev.c
> index 150f8d8..7cb7085 100644
> --- a/lib/netdev.c
> +++ b/lib/netdev.c
> @@ -377,6 +377,8 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp)
>                  netdev->netdev_class = rc->class;
>                  netdev->name = xstrdup(name);
>                  netdev->change_seq = 1;
> +                netdev->reconfigure_seq = seq_create();
> +                netdev->last_reconfigure_seq = seq_read(netdev->reconfigure_seq);
>                  netdev->node = shash_add(&netdev_shash, name, netdev);
>  
>                  /* By default enable one tx and rx queue per netdev. */
> @@ -525,6 +527,7 @@ netdev_unref(struct netdev *dev)
>              shash_delete(&netdev_shash, dev->node);
>          }
>          free(dev->name);
> +        seq_destroy(dev->reconfigure_seq);
>          dev->netdev_class->dealloc(dev);
>          ovs_mutex_unlock(&netdev_mutex);
>  
> @@ -1854,3 +1857,38 @@ netdev_get_change_seq(const struct netdev *netdev)
>  {
>      return netdev->change_seq;
>  }
> +
> +void
> +netdev_wait_reconf_required(struct netdev *netdev)
> +{
> +    seq_wait(netdev->reconfigure_seq, netdev->last_reconfigure_seq);
> +}
> +
> +bool
> +netdev_is_reconf_required(struct netdev *netdev)
> +{
> +    return seq_read(netdev->reconfigure_seq) != netdev->last_reconfigure_seq;
> +}
> +
> +/* Give a chance to 'netdev' to reconfigure some of its parameters.
> + *
> + * If a module uses netdev_send() and netdev_rxq_recv(), it must call this
> + * function when netdev_is_reconf_required() returns true.
> + *
> + * Return 0 if successful, otherwise a positive errno value.  If the
> + * reconfiguration fails the netdev will not be able to send or receive
> + * packets.
> + *
> + * When this function is called, no concurrent call to netdev_rxq_recv() or
> + * netdev_send() must be issued. */

Not only concurrent. There must be no calls at all.

> +int
> +netdev_reconfigure(struct netdev *netdev)
> +{
> +    const struct netdev_class *class = netdev->netdev_class;
> +
> +    netdev->last_reconfigure_seq = seq_read(netdev->reconfigure_seq);
> +
> +    return (class->reconfigure
> +            ? class->reconfigure(netdev)
> +            : EOPNOTSUPP);
> +}
> diff --git a/lib/netdev.h b/lib/netdev.h
> index a81989e..c2a1d6c 100644
> --- a/lib/netdev.h
> +++ b/lib/netdev.h
> @@ -308,6 +308,10 @@ int netdev_get_queue_stats(const struct netdev *, unsigned int queue_id,
>                             struct netdev_queue_stats *);
>  uint64_t netdev_get_change_seq(const struct netdev *);
>  
> +int netdev_reconfigure(struct netdev *netdev);
> +void netdev_wait_reconf_required(struct netdev *netdev);
> +bool netdev_is_reconf_required(struct netdev *netdev);
> +
>  struct netdev_queue_dump {
>      struct netdev *netdev;
>      int error;
>
Daniele Di Proietto March 16, 2016, 11:04 p.m. UTC | #2
On 16/03/2016 06:12, "Ilya Maximets" <i.maximets@samsung.com> wrote:

>On 16.03.2016 01:30, Daniele Di Proietto wrote:
>> A netdev provider, especially a PMD provider (like netdev DPDK) might
>> not be able to change some of its parameters (such as MTU, or number of
>> queues) without stopping everything and restarting.
>> 
>> This commit introduces a mechanism that allows a netdev provider to
>> request a restart (netdev_request_reconfigure()).  The upper layer can
>> be notified via netdev_wait_reconf_required() and
>> netdev_is_reconf_required().  After closing all the rxqs the upper layer
>> can finally call netdev_reconfigure(), to make sure that the new
>> configuration is in place.
>> 
>> This will be used by next commit to reconfigure rx and tx queues in
>> netdev-dpdk.
>> 
>> Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
>> ---
>>  lib/netdev-bsd.c      |  1 +
>>  lib/netdev-dpdk.c     |  1 +
>>  lib/netdev-dummy.c    |  1 +
>>  lib/netdev-linux.c    |  1 +
>>  lib/netdev-provider.h | 27 ++++++++++++++++++++++++++-
>>  lib/netdev-vport.c    |  1 +
>>  lib/netdev.c          | 38 ++++++++++++++++++++++++++++++++++++++
>>  lib/netdev.h          |  4 ++++
>>  8 files changed, 73 insertions(+), 1 deletion(-)
>> 
>> diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
>> index edf04bf..724e6d4 100644
>> --- a/lib/netdev-bsd.c
>> +++ b/lib/netdev-bsd.c
>> @@ -1602,6 +1602,7 @@ netdev_bsd_update_flags(struct netdev *netdev_,
>>enum netdev_flags off,
>>      netdev_bsd_arp_lookup, /* arp_lookup */          \
>>                                                       \
>>      netdev_bsd_update_flags,                         \
>> +    NULL, /* reconfigure */                          \
>>                                                       \
>>      netdev_bsd_rxq_alloc,                            \
>>      netdev_bsd_rxq_construct,                        \
>> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
>> index f402354..b5867e8 100644
>> --- a/lib/netdev-dpdk.c
>> +++ b/lib/netdev-dpdk.c
>> @@ -2696,6 +2696,7 @@ static const struct dpdk_qos_ops
>>egress_policer_ops = {
>>      NULL,                       /* arp_lookup */              \
>>                                                                \
>>      netdev_dpdk_update_flags,                                 \
>> +    NULL,                       /* reconfigure */             \
>>                                                                \
>>      netdev_dpdk_rxq_alloc,                                    \
>>      netdev_dpdk_rxq_construct,                                \
>> diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
>> index ccd4a0a..d7524eb 100644
>> --- a/lib/netdev-dummy.c
>> +++ b/lib/netdev-dummy.c
>> @@ -1251,6 +1251,7 @@ static const struct netdev_class dummy_class = {
>>      NULL,                       /* arp_lookup */
>>  
>>      netdev_dummy_update_flags,
>> +    NULL,                       /* reconfigure */
>>  
>>      netdev_dummy_rxq_alloc,
>>      netdev_dummy_rxq_construct,
>> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
>> index 570677e..f9ad126 100644
>> --- a/lib/netdev-linux.c
>> +++ b/lib/netdev-linux.c
>> @@ -2897,6 +2897,7 @@ netdev_linux_update_flags(struct netdev *netdev_,
>>enum netdev_flags off,
>>      netdev_linux_arp_lookup,                                    \
>>                                                                  \
>>      netdev_linux_update_flags,                                  \
>> +    NULL,                       /* reconfigure */               \
>>                                                                  \
>>      netdev_linux_rxq_alloc,                                     \
>>      netdev_linux_rxq_construct,                                 \
>> diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
>> index 1952a02..0317910 100644
>> --- a/lib/netdev-provider.h
>> +++ b/lib/netdev-provider.h
>> @@ -52,6 +52,16 @@ struct netdev {
>>       * 'netdev''s flags, features, ethernet address, or carrier
>>changes. */
>>      uint64_t change_seq;
>>  
>> +    /* A netdev provider might be unable to change some of the device's
>> +     * parameter (n_rxq, mtu) when the device is in use.  In this case
>> +     * the provider can notify the upper layer by calling
>> +     * netdev_request_reconfigure().  The upper layer will react by
>>stopping
>> +     * the operations on the device and calling netdev_reconfigure()
>>to allow
>> +     * the configuration changes.  'last_reconfigure_seq' remembers
>>the value
>> +     * of 'reconfigure_seq' when the last reconfiguration happened. */
>> +    struct seq *reconfigure_seq;
>> +    uint64_t last_reconfigure_seq;
>> +
>>      /* The core netdev code initializes these at netdev construction
>>and only
>>       * provide read-only access to its client.  Netdev implementations
>>may
>>       * modify them. */
>> @@ -64,7 +74,7 @@ struct netdev {
>>      struct ovs_list saved_flags_list; /* Contains "struct
>>netdev_saved_flags". */
>>  };
>>  
>> -static void
>> +static inline void
>>  netdev_change_seq_changed(const struct netdev *netdev_)
>>  {
>>      struct netdev *netdev = CONST_CAST(struct netdev *, netdev_);
>> @@ -75,6 +85,12 @@ netdev_change_seq_changed(const struct netdev
>>*netdev_)
>>      }
>>  }
>>  
>> +static inline void
>> +netdev_request_reconfigure(struct netdev *netdev)
>> +{
>> +    seq_change(netdev->reconfigure_seq);
>> +}
>> +
>>  const char *netdev_get_type(const struct netdev *);
>>  const struct netdev_class *netdev_get_class(const struct netdev *);
>>  const char *netdev_get_name(const struct netdev *);
>> @@ -699,6 +715,15 @@ struct netdev_class {
>>      int (*update_flags)(struct netdev *netdev, enum netdev_flags off,
>>                          enum netdev_flags on, enum netdev_flags
>>*old_flags);
>>  
>> +    /* If the provider called netdev_request_reconfigure(), the upper
>>layer
>> +     * will eventually call this.  The provider can update the device
>> +     * configuration knowing that the upper layer will not call
>>rxq_recv() or
>> +     * send() until this function returns.
>> +     *
>> +     * On error, the configuration is indeterminant and the device
>>cannot be
>> +     * used to send and receive packets until a successful
>>configuration is
>> +     * applied. */
>> +    int (*reconfigure)(struct netdev *netdev);
>>  /* ## -------------------- ## */
>>  /* ## netdev_rxq Functions ## */
>>  /* ## -------------------- ## */
>> diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
>> index df6d8cf..d055f10 100644
>> --- a/lib/netdev-vport.c
>> +++ b/lib/netdev-vport.c
>> @@ -1537,6 +1537,7 @@ netdev_vport_range(struct unixctl_conn *conn, int
>>argc,
>>      NULL,                       /* arp_lookup */            \
>>                                                              \
>>      netdev_vport_update_flags,                              \
>> +    NULL,                       /* reconfigure */           \
>>                                                              \
>>      NULL,                   /* rx_alloc */                  \
>>      NULL,                   /* rx_construct */              \
>> diff --git a/lib/netdev.c b/lib/netdev.c
>> index 150f8d8..7cb7085 100644
>> --- a/lib/netdev.c
>> +++ b/lib/netdev.c
>> @@ -377,6 +377,8 @@ netdev_open(const char *name, const char *type,
>>struct netdev **netdevp)
>>                  netdev->netdev_class = rc->class;
>>                  netdev->name = xstrdup(name);
>>                  netdev->change_seq = 1;
>> +                netdev->reconfigure_seq = seq_create();
>> +                netdev->last_reconfigure_seq =
>>seq_read(netdev->reconfigure_seq);
>>                  netdev->node = shash_add(&netdev_shash, name, netdev);
>>  
>>                  /* By default enable one tx and rx queue per netdev. */
>> @@ -525,6 +527,7 @@ netdev_unref(struct netdev *dev)
>>              shash_delete(&netdev_shash, dev->node);
>>          }
>>          free(dev->name);
>> +        seq_destroy(dev->reconfigure_seq);
>>          dev->netdev_class->dealloc(dev);
>>          ovs_mutex_unlock(&netdev_mutex);
>>  
>> @@ -1854,3 +1857,38 @@ netdev_get_change_seq(const struct netdev
>>*netdev)
>>  {
>>      return netdev->change_seq;
>>  }
>> +
>> +void
>> +netdev_wait_reconf_required(struct netdev *netdev)
>> +{
>> +    seq_wait(netdev->reconfigure_seq, netdev->last_reconfigure_seq);
>> +}
>> +
>> +bool
>> +netdev_is_reconf_required(struct netdev *netdev)
>> +{
>> +    return seq_read(netdev->reconfigure_seq) !=
>>netdev->last_reconfigure_seq;
>> +}
>> +
>> +/* Give a chance to 'netdev' to reconfigure some of its parameters.
>> + *
>> + * If a module uses netdev_send() and netdev_rxq_recv(), it must call
>>this
>> + * function when netdev_is_reconf_required() returns true.
>> + *
>> + * Return 0 if successful, otherwise a positive errno value.  If the
>> + * reconfiguration fails the netdev will not be able to send or receive
>> + * packets.
>> + *
>> + * When this function is called, no concurrent call to
>>netdev_rxq_recv() or
>> + * netdev_send() must be issued. */
>
>Not only concurrent. There must be no calls at all.
>
>> +int
>> +netdev_reconfigure(struct netdev *netdev)
>> +{
>> +    const struct netdev_class *class = netdev->netdev_class;
>> +
>> +    netdev->last_reconfigure_seq = seq_read(netdev->reconfigure_seq);
>> +
>> +    return (class->reconfigure
>> +            ? class->reconfigure(netdev)
>> +            : EOPNOTSUPP);
>> +}
>> diff --git a/lib/netdev.h b/lib/netdev.h
>> index a81989e..c2a1d6c 100644
>> --- a/lib/netdev.h
>> +++ b/lib/netdev.h
>> @@ -308,6 +308,10 @@ int netdev_get_queue_stats(const struct netdev *,
>>unsigned int queue_id,
>>                             struct netdev_queue_stats *);
>>  uint64_t netdev_get_change_seq(const struct netdev *);
>>  
>> +int netdev_reconfigure(struct netdev *netdev);
>> +void netdev_wait_reconf_required(struct netdev *netdev);
>> +bool netdev_is_reconf_required(struct netdev *netdev);
>> +
>>  struct netdev_queue_dump {
>>      struct netdev *netdev;
>>      int error;
>>
Daniele Di Proietto March 16, 2016, 11:36 p.m. UTC | #3
On 16/03/2016 06:12, "Ilya Maximets" <i.maximets@samsung.com> wrote:

>On 16.03.2016 01:30, Daniele Di Proietto wrote:
>> A netdev provider, especially a PMD provider (like netdev DPDK) might
>> not be able to change some of its parameters (such as MTU, or number of
>> queues) without stopping everything and restarting.
>> 
>> This commit introduces a mechanism that allows a netdev provider to
>> request a restart (netdev_request_reconfigure()).  The upper layer can
>> be notified via netdev_wait_reconf_required() and
>> netdev_is_reconf_required().  After closing all the rxqs the upper layer
>> can finally call netdev_reconfigure(), to make sure that the new
>> configuration is in place.
>> 
>> This will be used by next commit to reconfigure rx and tx queues in
>> netdev-dpdk.
>> 
>> Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>

[...]

>>
>>  
>> @@ -1854,3 +1857,38 @@ netdev_get_change_seq(const struct netdev
>>*netdev)
>>  {
>>      return netdev->change_seq;
>>  }
>> +
>> +void
>> +netdev_wait_reconf_required(struct netdev *netdev)
>> +{
>> +    seq_wait(netdev->reconfigure_seq, netdev->last_reconfigure_seq);
>> +}
>> +
>> +bool
>> +netdev_is_reconf_required(struct netdev *netdev)
>> +{
>> +    return seq_read(netdev->reconfigure_seq) !=
>>netdev->last_reconfigure_seq;
>> +}
>> +
>> +/* Give a chance to 'netdev' to reconfigure some of its parameters.
>> + *
>> + * If a module uses netdev_send() and netdev_rxq_recv(), it must call
>>this
>> + * function when netdev_is_reconf_required() returns true.
>> + *
>> + * Return 0 if successful, otherwise a positive errno value.  If the
>> + * reconfiguration fails the netdev will not be able to send or receive
>> + * packets.
>> + *
>> + * When this function is called, no concurrent call to
>>netdev_rxq_recv() or
>> + * netdev_send() must be issued. */
>
>Not only concurrent. There must be no calls at all.

By "concurrent" I meant concurrent to netdev_reconfigure().  Since, as you
point out,
this is confusing, I've changed the comment to:

 * When this function is called, no call to netdev_rxq_recv() or
netdev_send()
 * must be issued. */
diff mbox

Patch

diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index edf04bf..724e6d4 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -1602,6 +1602,7 @@  netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
     netdev_bsd_arp_lookup, /* arp_lookup */          \
                                                      \
     netdev_bsd_update_flags,                         \
+    NULL, /* reconfigure */                          \
                                                      \
     netdev_bsd_rxq_alloc,                            \
     netdev_bsd_rxq_construct,                        \
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index f402354..b5867e8 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -2696,6 +2696,7 @@  static const struct dpdk_qos_ops egress_policer_ops = {
     NULL,                       /* arp_lookup */              \
                                                               \
     netdev_dpdk_update_flags,                                 \
+    NULL,                       /* reconfigure */             \
                                                               \
     netdev_dpdk_rxq_alloc,                                    \
     netdev_dpdk_rxq_construct,                                \
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index ccd4a0a..d7524eb 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1251,6 +1251,7 @@  static const struct netdev_class dummy_class = {
     NULL,                       /* arp_lookup */
 
     netdev_dummy_update_flags,
+    NULL,                       /* reconfigure */
 
     netdev_dummy_rxq_alloc,
     netdev_dummy_rxq_construct,
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 570677e..f9ad126 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -2897,6 +2897,7 @@  netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
     netdev_linux_arp_lookup,                                    \
                                                                 \
     netdev_linux_update_flags,                                  \
+    NULL,                       /* reconfigure */               \
                                                                 \
     netdev_linux_rxq_alloc,                                     \
     netdev_linux_rxq_construct,                                 \
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 1952a02..0317910 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -52,6 +52,16 @@  struct netdev {
      * 'netdev''s flags, features, ethernet address, or carrier changes. */
     uint64_t change_seq;
 
+    /* A netdev provider might be unable to change some of the device's
+     * parameter (n_rxq, mtu) when the device is in use.  In this case
+     * the provider can notify the upper layer by calling
+     * netdev_request_reconfigure().  The upper layer will react by stopping
+     * the operations on the device and calling netdev_reconfigure() to allow
+     * the configuration changes.  'last_reconfigure_seq' remembers the value
+     * of 'reconfigure_seq' when the last reconfiguration happened. */
+    struct seq *reconfigure_seq;
+    uint64_t last_reconfigure_seq;
+
     /* The core netdev code initializes these at netdev construction and only
      * provide read-only access to its client.  Netdev implementations may
      * modify them. */
@@ -64,7 +74,7 @@  struct netdev {
     struct ovs_list saved_flags_list; /* Contains "struct netdev_saved_flags". */
 };
 
-static void
+static inline void
 netdev_change_seq_changed(const struct netdev *netdev_)
 {
     struct netdev *netdev = CONST_CAST(struct netdev *, netdev_);
@@ -75,6 +85,12 @@  netdev_change_seq_changed(const struct netdev *netdev_)
     }
 }
 
+static inline void
+netdev_request_reconfigure(struct netdev *netdev)
+{
+    seq_change(netdev->reconfigure_seq);
+}
+
 const char *netdev_get_type(const struct netdev *);
 const struct netdev_class *netdev_get_class(const struct netdev *);
 const char *netdev_get_name(const struct netdev *);
@@ -699,6 +715,15 @@  struct netdev_class {
     int (*update_flags)(struct netdev *netdev, enum netdev_flags off,
                         enum netdev_flags on, enum netdev_flags *old_flags);
 
+    /* If the provider called netdev_request_reconfigure(), the upper layer
+     * will eventually call this.  The provider can update the device
+     * configuration knowing that the upper layer will not call rxq_recv() or
+     * send() until this function returns.
+     *
+     * On error, the configuration is indeterminant and the device cannot be
+     * used to send and receive packets until a successful configuration is
+     * applied. */
+    int (*reconfigure)(struct netdev *netdev);
 /* ## -------------------- ## */
 /* ## netdev_rxq Functions ## */
 /* ## -------------------- ## */
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index df6d8cf..d055f10 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -1537,6 +1537,7 @@  netdev_vport_range(struct unixctl_conn *conn, int argc,
     NULL,                       /* arp_lookup */            \
                                                             \
     netdev_vport_update_flags,                              \
+    NULL,                       /* reconfigure */           \
                                                             \
     NULL,                   /* rx_alloc */                  \
     NULL,                   /* rx_construct */              \
diff --git a/lib/netdev.c b/lib/netdev.c
index 150f8d8..7cb7085 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -377,6 +377,8 @@  netdev_open(const char *name, const char *type, struct netdev **netdevp)
                 netdev->netdev_class = rc->class;
                 netdev->name = xstrdup(name);
                 netdev->change_seq = 1;
+                netdev->reconfigure_seq = seq_create();
+                netdev->last_reconfigure_seq = seq_read(netdev->reconfigure_seq);
                 netdev->node = shash_add(&netdev_shash, name, netdev);
 
                 /* By default enable one tx and rx queue per netdev. */
@@ -525,6 +527,7 @@  netdev_unref(struct netdev *dev)
             shash_delete(&netdev_shash, dev->node);
         }
         free(dev->name);
+        seq_destroy(dev->reconfigure_seq);
         dev->netdev_class->dealloc(dev);
         ovs_mutex_unlock(&netdev_mutex);
 
@@ -1854,3 +1857,38 @@  netdev_get_change_seq(const struct netdev *netdev)
 {
     return netdev->change_seq;
 }
+
+void
+netdev_wait_reconf_required(struct netdev *netdev)
+{
+    seq_wait(netdev->reconfigure_seq, netdev->last_reconfigure_seq);
+}
+
+bool
+netdev_is_reconf_required(struct netdev *netdev)
+{
+    return seq_read(netdev->reconfigure_seq) != netdev->last_reconfigure_seq;
+}
+
+/* Give a chance to 'netdev' to reconfigure some of its parameters.
+ *
+ * If a module uses netdev_send() and netdev_rxq_recv(), it must call this
+ * function when netdev_is_reconf_required() returns true.
+ *
+ * Return 0 if successful, otherwise a positive errno value.  If the
+ * reconfiguration fails the netdev will not be able to send or receive
+ * packets.
+ *
+ * When this function is called, no concurrent call to netdev_rxq_recv() or
+ * netdev_send() must be issued. */
+int
+netdev_reconfigure(struct netdev *netdev)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    netdev->last_reconfigure_seq = seq_read(netdev->reconfigure_seq);
+
+    return (class->reconfigure
+            ? class->reconfigure(netdev)
+            : EOPNOTSUPP);
+}
diff --git a/lib/netdev.h b/lib/netdev.h
index a81989e..c2a1d6c 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -308,6 +308,10 @@  int netdev_get_queue_stats(const struct netdev *, unsigned int queue_id,
                            struct netdev_queue_stats *);
 uint64_t netdev_get_change_seq(const struct netdev *);
 
+int netdev_reconfigure(struct netdev *netdev);
+void netdev_wait_reconf_required(struct netdev *netdev);
+bool netdev_is_reconf_required(struct netdev *netdev);
+
 struct netdev_queue_dump {
     struct netdev *netdev;
     int error;