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 <diproiet...@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 | 23 ++++++++++++++++++++++- lib/netdev-vport.c | 1 + lib/netdev.c | 29 +++++++++++++++++++++++++++++ lib/netdev.h | 4 ++++ 8 files changed, 60 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 b3518b8..a48ca71 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -2298,6 +2298,7 @@ unlock_dpdk: 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 d58c1b1..d7599c3 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -2888,6 +2888,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 2aa1b5d..9646cca 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,11 @@ 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. */ + 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 ee92e01..2c0918b 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,29 @@ 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; +} + +/* 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; -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev