Message ID | 1458081003-82542-11-git-send-email-diproiettod@vmware.com |
---|---|
State | Superseded, archived |
Headers | show |
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; >
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; >>
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 --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;
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(-)