[PATCH] libc: move pthread_barrier to a separate file
As @nyh noted in #823 gcc 4.8 doesn't like both using and redefining pthread_mutex_lock in the same file. This is a workaround for what seems to be a compiler bug. The code using pthread_mutex_lock/unlock (pthread_barrier_* functions) is moved to a new .cc file. Fixes #823 Signed-off-by: Justin Cinkelj --- Makefile| 1 + libc/pthread.cc | 116 +--- libc/pthread_barrier.cc | 126 3 files changed, 128 insertions(+), 115 deletions(-) create mode 100644 libc/pthread_barrier.cc diff --git a/Makefile b/Makefile index cf58c0a..bca37eb 100644 --- a/Makefile +++ b/Makefile @@ -1652,6 +1652,7 @@ musl += regex/tre-mem.o $(out)/musl/src/regex/tre-mem.o: CFLAGS += -UNDEBUG libc += pthread.o +libc += pthread_barrier.o libc += libc.o libc += dlfcn.o libc += time.o diff --git a/libc/pthread.cc b/libc/pthread.cc index 62de17d..a2b9292 100644 --- a/libc/pthread.cc +++ b/libc/pthread.cc @@ -29,7 +29,7 @@ #include #include -#include + #include "pthread.hh" namespace pthread_private { @@ -1128,117 +1128,3 @@ int pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, return 0; } - -// Private definitions of the internal structs backing pthread_barrier_t and -// pthread_barrierattr_t -typedef struct -{ -unsigned int out; -unsigned int count; -latch *ltch; -pthread_mutex_t *mtx; -} pthread_barrier_t_int; - -typedef struct -{ -unsigned pshared; -} pthread_barrierattr_t_int; - -int pthread_barrier_init(pthread_barrier_t *barrier_opq, - const pthread_barrierattr_t *attr_opq, - unsigned count) -{ -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; -static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t), - "pthread_barrier_t_int is larger than pthread_barrier_t"); - -// Linux returns EINVAL if count == 0 or INT_MAX so we do too. -// In theory, we could go up to UINT_MAX since count is unsigned. -if (!barrier || count == 0 || count >= INT_MAX) { -return EINVAL; -} - -// Always ignore attr, it has no meaning in the context of a unikernel. -// pthread_barrierattr_t has a single member variable pshared that can be set -// to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED. These have the -// same effect in a unikernel - there is only a single process and all -// threads can manipulate the memory area associated with the -// pthread_barrier_t so it doesn't matter what the value of pshared is set to -barrier->count = count; -barrier->out = 0; -barrier->ltch = new latch(count); -barrier->mtx = new pthread_mutex_t; -pthread_mutex_init(barrier->mtx, NULL); -return 0; -} - -int pthread_barrier_wait(pthread_barrier_t *barrier_opq) -{ -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; -static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t), - "pthread_barrier_t_int is larger than pthread_barrier_t"); - -if (!barrier || !barrier->ltch || !barrier->mtx) { -return EINVAL; -} - -int retval = 0; -pthread_mutex_t *mtx = barrier->mtx; - -pthread_mutex_lock(mtx); -pthread_mutex_unlock(mtx); - -latch *l = barrier->ltch; -l->count_down(); -// All threads stuck here until we get at least 'count' waiters -l->await(); - -// If the last thread (thread x) to wait on the barrier is descheduled here -// (immediately after being the count'th thread crossing the barrier) -// the barrier remains open (a new waiting thread will cross) until -// the barrier is reset below (when thread x is rescheduled), which doesn't -// seem technically incorrect. Only one of the crossing threads will get a -// retval of PTHREAD_BARRIER_SERIAL_THREAD, when -// barrier->out == barrier->count. -// All other crossing threads will get a retval of 0. - -pthread_mutex_lock(mtx); -barrier->out++; -// Make the last thread out responsible for resetting the barrier's latch. -// The last thread also gets the special return value -// PTHREAD_BARRIER_SERIAL_THREAD. Every other thread gets a retval of 0 -if (barrier->out == barrier->count) { -retval = PTHREAD_BARRIER_SERIAL_THREAD; -// Reset the latch for the next round of waiters. We're using an -// external lock (mtx) to ensure that no other thread is calling -// count_down or in await when we're resetting it. Without the external -// lock, resetting the latch isn't safe. -l->unsafe_reset(barrier->count); -// Reset the 'out' counter so that the equality check above works across -// multiple rounds of threads waiting on the barrier -barrier->out = 0; -} -pthread_mutex_unlock(mtx); -return retval; -} - -int pthread_barrier_destroy
Re: [PATCH] libc: move pthread_barrier to a separate file
On Wed, Dec 28, 2016 at 10:19 PM, Justin Cinkelj wrote: > As @nyh noted in #823 gcc 4.8 doesn't like both using and redefining > pthread_mutex_lock in the same file. This is a workaround for what > seems to be a compiler bug. The code using pthread_mutex_lock/unlock > (pthread_barrier_* functions) is moved to a new .cc file. > > Fixes #823 > Thanks! I was planning to change latch.hh to not use std::mutex (and use OSv's "mutex" instead... it would also have a lower overhead), but your fix is easier, so let's go with it. Thanks. > > Signed-off-by: Justin Cinkelj > --- > Makefile| 1 + > libc/pthread.cc | 116 +- > -- > libc/pthread_barrier.cc | 126 ++ > ++ > 3 files changed, 128 insertions(+), 115 deletions(-) > create mode 100644 libc/pthread_barrier.cc > > diff --git a/Makefile b/Makefile > index cf58c0a..bca37eb 100644 > --- a/Makefile > +++ b/Makefile > @@ -1652,6 +1652,7 @@ musl += regex/tre-mem.o > $(out)/musl/src/regex/tre-mem.o: CFLAGS += -UNDEBUG > > libc += pthread.o > +libc += pthread_barrier.o > libc += libc.o > libc += dlfcn.o > libc += time.o > diff --git a/libc/pthread.cc b/libc/pthread.cc > index 62de17d..a2b9292 100644 > --- a/libc/pthread.cc > +++ b/libc/pthread.cc > @@ -29,7 +29,7 @@ > > #include > #include > -#include > + > #include "pthread.hh" > > namespace pthread_private { > @@ -1128,117 +1128,3 @@ int pthread_attr_getaffinity_np(const > pthread_attr_t *attr, size_t cpusetsize, > > return 0; > } > - > -// Private definitions of the internal structs backing pthread_barrier_t > and > -// pthread_barrierattr_t > -typedef struct > -{ > -unsigned int out; > -unsigned int count; > -latch *ltch; > -pthread_mutex_t *mtx; > -} pthread_barrier_t_int; > - > -typedef struct > -{ > -unsigned pshared; > -} pthread_barrierattr_t_int; > - > -int pthread_barrier_init(pthread_barrier_t *barrier_opq, > - const pthread_barrierattr_t *attr_opq, > - unsigned count) > -{ > -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; > -static_assert(sizeof(pthread_barrier_t_int) <= > sizeof(pthread_barrier_t), > - "pthread_barrier_t_int is larger than > pthread_barrier_t"); > - > -// Linux returns EINVAL if count == 0 or INT_MAX so we do too. > -// In theory, we could go up to UINT_MAX since count is unsigned. > -if (!barrier || count == 0 || count >= INT_MAX) { > -return EINVAL; > -} > - > -// Always ignore attr, it has no meaning in the context of a > unikernel. > -// pthread_barrierattr_t has a single member variable pshared that > can be set > -// to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED. These have > the > -// same effect in a unikernel - there is only a single process and all > -// threads can manipulate the memory area associated with the > -// pthread_barrier_t so it doesn't matter what the value of pshared > is set to > -barrier->count = count; > -barrier->out = 0; > -barrier->ltch = new latch(count); > -barrier->mtx = new pthread_mutex_t; > -pthread_mutex_init(barrier->mtx, NULL); > -return 0; > -} > - > -int pthread_barrier_wait(pthread_barrier_t *barrier_opq) > -{ > -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; > -static_assert(sizeof(pthread_barrier_t_int) <= > sizeof(pthread_barrier_t), > - "pthread_barrier_t_int is larger than > pthread_barrier_t"); > - > -if (!barrier || !barrier->ltch || !barrier->mtx) { > -return EINVAL; > -} > - > -int retval = 0; > -pthread_mutex_t *mtx = barrier->mtx; > - > -pthread_mutex_lock(mtx); > -pthread_mutex_unlock(mtx); > - > -latch *l = barrier->ltch; > -l->count_down(); > -// All threads stuck here until we get at least 'count' waiters > -l->await(); > - > -// If the last thread (thread x) to wait on the barrier is > descheduled here > -// (immediately after being the count'th thread crossing the barrier) > -// the barrier remains open (a new waiting thread will cross) until > -// the barrier is reset below (when thread x is rescheduled), which > doesn't > -// seem technically incorrect. Only one of the crossing threads will > get a > -// retval of PTHREAD_BARRIER_SERIAL_THREAD, when > -// barrier->out == barrier->count. > -// All other crossing threads will get a retval of 0. > - > -pthread_mutex_lock(mtx); > -barrier->out++; > -// Make the last thread out responsible for resetting the barrier's > latch. > -// The last thread also gets the special return value > -// PTHREAD_BARRIER_SERIAL_THREAD. Every other thread gets a retval of > 0 > -if (barrier->out == barrier->count) { > -retval = PTHREAD_BARRIER_SERIAL_THREAD; > -// Reset the latch for the next round of waiters.
[COMMIT osv master] libc: move pthread_barrier to a separate file
From: Justin Cinkelj Committer: Nadav Har'El Branch: master libc: move pthread_barrier to a separate file As @nyh noted in #823 gcc 4.8 doesn't like both using and redefining pthread_mutex_lock in the same file. This is a workaround for what seems to be a compiler bug. The code using pthread_mutex_lock/unlock (pthread_barrier_* functions) is moved to a new .cc file. Fixes #823 Signed-off-by: Justin Cinkelj Message-Id: <20161228201949.7322-1-justin.cink...@xlab.si> --- diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -1652,6 +1652,7 @@ musl += regex/tre-mem.o $(out)/musl/src/regex/tre-mem.o: CFLAGS += -UNDEBUG libc += pthread.o +libc += pthread_barrier.o libc += libc.o libc += dlfcn.o libc += time.o diff --git a/libc/pthread.cc b/libc/pthread.cc --- a/libc/pthread.cc +++ b/libc/pthread.cc @@ -29,7 +29,7 @@ #include #include -#include + #include "pthread.hh" namespace pthread_private { @@ -1128,117 +1128,3 @@ int pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, return 0; } - -// Private definitions of the internal structs backing pthread_barrier_t and -// pthread_barrierattr_t -typedef struct -{ -unsigned int out; -unsigned int count; -latch *ltch; -pthread_mutex_t *mtx; -} pthread_barrier_t_int; - -typedef struct -{ -unsigned pshared; -} pthread_barrierattr_t_int; - -int pthread_barrier_init(pthread_barrier_t *barrier_opq, - const pthread_barrierattr_t *attr_opq, - unsigned count) -{ -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; -static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t), - "pthread_barrier_t_int is larger than pthread_barrier_t"); - -// Linux returns EINVAL if count == 0 or INT_MAX so we do too. -// In theory, we could go up to UINT_MAX since count is unsigned. -if (!barrier || count == 0 || count >= INT_MAX) { -return EINVAL; -} - -// Always ignore attr, it has no meaning in the context of a unikernel. -// pthread_barrierattr_t has a single member variable pshared that can be set -// to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED. These have the -// same effect in a unikernel - there is only a single process and all -// threads can manipulate the memory area associated with the -// pthread_barrier_t so it doesn't matter what the value of pshared is set to -barrier->count = count; -barrier->out = 0; -barrier->ltch = new latch(count); -barrier->mtx = new pthread_mutex_t; -pthread_mutex_init(barrier->mtx, NULL); -return 0; -} - -int pthread_barrier_wait(pthread_barrier_t *barrier_opq) -{ -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; -static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t), - "pthread_barrier_t_int is larger than pthread_barrier_t"); - -if (!barrier || !barrier->ltch || !barrier->mtx) { -return EINVAL; -} - -int retval = 0; -pthread_mutex_t *mtx = barrier->mtx; - -pthread_mutex_lock(mtx); -pthread_mutex_unlock(mtx); - -latch *l = barrier->ltch; -l->count_down(); -// All threads stuck here until we get at least 'count' waiters -l->await(); - -// If the last thread (thread x) to wait on the barrier is descheduled here -// (immediately after being the count'th thread crossing the barrier) -// the barrier remains open (a new waiting thread will cross) until -// the barrier is reset below (when thread x is rescheduled), which doesn't -// seem technically incorrect. Only one of the crossing threads will get a -// retval of PTHREAD_BARRIER_SERIAL_THREAD, when -// barrier->out == barrier->count. -// All other crossing threads will get a retval of 0. - -pthread_mutex_lock(mtx); -barrier->out++; -// Make the last thread out responsible for resetting the barrier's latch. -// The last thread also gets the special return value -// PTHREAD_BARRIER_SERIAL_THREAD. Every other thread gets a retval of 0 -if (barrier->out == barrier->count) { -retval = PTHREAD_BARRIER_SERIAL_THREAD; -// Reset the latch for the next round of waiters. We're using an -// external lock (mtx) to ensure that no other thread is calling -// count_down or in await when we're resetting it. Without the external -// lock, resetting the latch isn't safe. -l->unsafe_reset(barrier->count); -// Reset the 'out' counter so that the equality check above works across -// multiple rounds of threads waiting on the barrier -barrier->out = 0; -} -pthread_mutex_unlock(mtx); -return retval; -} - -int pthread_barrier_destroy(pthread_barrier_t *barrier_opq) -{ -pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq; - -static_assert(sizeof(pthrea
[COMMIT osv master] osv::run const correctness
From: Nadav Har'El Committer: Nadav Har'El Branch: master osv::run const correctness The variant of osv::run which takes argv does not need the strings or their array to be writable, since it copies them into an std::vector anyway, so we can take a const char* const* instead of a char**. Also fix non-const string warnings in tst-run.cc. Signed-off-by: Nadav Har'El --- diff --git a/core/run.cc b/core/run.cc --- a/core/run.cc +++ b/core/run.cc @@ -16,7 +16,7 @@ std::shared_ptr run(std::string path, } std::shared_ptr run(std::string path, - int argc, char** argv, int *return_code) + int argc, const char* const* argv, int *return_code) { std::vector args; for (int i = 0; i < argc; i++) { diff --git a/include/osv/run.hh b/include/osv/run.hh --- a/include/osv/run.hh +++ b/include/osv/run.hh @@ -78,7 +78,7 @@ namespace osv { * \return \c shared pointer to the application */ std::shared_ptr run(std::string path, - int argc, char** argv, int *return_code); + int argc, const char* const* argv, int *return_code); /** * Run the given executable. diff --git a/tests/tst-run.cc b/tests/tst-run.cc --- a/tests/tst-run.cc +++ b/tests/tst-run.cc @@ -31,7 +31,7 @@ int main(int ac, char** av) } // See that I can run myself (with a special argument to stop the recursion) -char *child_args[] = {"/tests/tst-run.so", ""}; +const char *child_args[] = {"/tests/tst-run.so", ""}; int ret; bool b = (bool)osv::run("/tests/tst-run.so", 2, child_args, &ret); report(b == true, "Run myself"); -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[PATCH v2] dhcp: do not release assigned IP just to update DNS name
We want to propagate new hostname to DNS server via DHCP server. Previously, a DHCP release followed by a new DORA cycle was used. This did update DNS name, but VM was for a short period of time without a valid IP. Now an early lease renew (with the new hostname included) is sent. Thus VM does not need to stop using assigned IP address. Fixes #816 Signed-off-by: Justin Cinkelj --- core/dhcp.cc | 46 +--- include/osv/dhcp.hh | 7 +- modules/cloud-init/cloud-init.cc | 10 - 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/core/dhcp.cc b/core/dhcp.cc index 0436837..662929c 100644 --- a/core/dhcp.cc +++ b/core/dhcp.cc @@ -72,10 +72,9 @@ void dhcp_release() net_dhcp_worker.release(); } -void dhcp_restart(bool wait) +void dhcp_renew(bool wait) { -net_dhcp_worker.release(); -net_dhcp_worker.start(wait); +net_dhcp_worker.renew(wait); } namespace dhcp { @@ -221,6 +220,9 @@ namespace dhcp { pkt->secs = 0; pkt->flags = 0; memcpy(pkt->chaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN); +ulong yip_n = htonl(yip.to_ulong()); +ulong sip_n = htonl(sip.to_ulong()); +memcpy(&pkt->ciaddr.s_addr, &yip_n, 4); // Options u8* options_start = reinterpret_cast(pkt+1); @@ -242,7 +244,7 @@ namespace dhcp { *options++ = DHCP_OPTION_END; dhcp_len += options - options_start; -build_udp_ip_headers(dhcp_len, INADDR_ANY, INADDR_BROADCAST); +build_udp_ip_headers(dhcp_len, yip_n, sip_n); } void dhcp_mbuf::compose_release(struct ifnet* ifp, @@ -541,6 +543,22 @@ namespace dhcp { _client_addr = _server_addr = ipv4_zero; } +void dhcp_interface_state::renew() +{ +// Update state +_state = DHCP_REQUEST; + +// Compose a dhcp request packet +dhcp_mbuf dm(false); +_xid = rand(); +dm.compose_request(_ifp, + _xid, + _client_addr, _server_addr); + +// Send +_sock->dhcp_send(dm); +} + void dhcp_interface_state::process_packet(struct mbuf* m) { dhcp_mbuf dm(true, m); @@ -692,13 +710,14 @@ namespace dhcp { _dhcp_thread->start(); } -void dhcp_worker::start(bool wait) +void dhcp_worker::_send_and_wait(bool wait, dhcp_interface_state_send_packet iface_func) { -// FIXME: clear routing table (use case run dhclient 2nd time) +// When doing renew, we still have IP, but want to reuse the flag. +_have_ip = false; do { -// Send discover packets! +// Send discover or renew packets! for (auto &it: _universe) { -it.second->discover(); +(it.second->*iface_func)(); } if (wait) { @@ -714,6 +733,12 @@ namespace dhcp { } while (!_have_ip && wait); } +void dhcp_worker::start(bool wait) +{ +// FIXME: clear routing table (use case run dhclient 2nd time) +_send_and_wait(wait, &dhcp_interface_state::discover); +} + void dhcp_worker::release() { for (auto &it: _universe) { @@ -724,6 +749,11 @@ namespace dhcp { usleep(1000); } +void dhcp_worker::renew(bool wait) +{ +_send_and_wait(wait, &dhcp_interface_state::renew); +} + void dhcp_worker::dhcp_worker_fn() { while (true) { diff --git a/include/osv/dhcp.hh b/include/osv/dhcp.hh index b286727..3db6df8 100644 --- a/include/osv/dhcp.hh +++ b/include/osv/dhcp.hh @@ -25,7 +25,7 @@ extern "C" { void dhcp_start(bool wait); void dhcp_release(); -void dhcp_restart(bool wait); +void dhcp_renew(bool wait); } namespace dhcp { @@ -226,6 +226,7 @@ namespace dhcp { void discover(); void release(); +void renew(); void process_packet(struct mbuf*); void state_discover(dhcp_mbuf &dm); void state_request(dhcp_mbuf &dm); @@ -242,6 +243,8 @@ namespace dhcp { // Transaction id u32 _xid; }; +// typedef for discover/renew functions +typedef void (dhcp_interface_state::*dhcp_interface_state_send_packet) (void); /// @@ -256,6 +259,7 @@ namespace dhcp { void start(bool wait); // Send release packet for all DHCP IPs. void release(); +void renew(bool wait); void dhcp_worker_fn(); void queue_packet(struct mbuf* m); @@ -270,6 +274,7 @@ namespace dhcp { // Wait for IP bool _have_ip; sched::thread * _waiter; +void _send_and_wait(bool wait, dhcp_interface_state_send_packet iface_func); }; } // namespace dhcp diff --git a/modules/cloud-init/cloud-init.cc b/modules/cloud-init/cloud-init.cc index e3ec8f8..acee13d 100644 --- a/modules/
Re: [PATCH] dhcp: do not release assigned IP just to update DNS name
You are right, the DORA cycle in dhcp_worker::start() retries inf-times until one iface gets IP. I didn't want to just copy-paste all dhcp_worker::start() code to the ::renew() (they both should at least print error/warning if reply is not received withing acceptable time - something you mentioned a few weeks ago, when I had problems with 'osv not booting" - so additional improvement is in place). So I renamed start() to _send_and_wait, and refactored it to accept pointer to function to be actually called. Now it is used by both start() and renew(). Justin - Original Message - > From: "Nadav Har'El" > To: "Justin Cinkelj" > Cc: "Osv Dev" > Sent: Sunday, December 25, 2016 10:42:24 PM > Subject: Re: [PATCH] dhcp: do not release assigned IP just to update DNS name > > In general, I think this is the right direction, but there's something I am > not sure I understand: It seems to me that the old code had a loop checking > that the new DHPC request worked. The current code, doesn't it just send > the updated DHCP request once, and forgets about it? It doesn't wait for it > to take effect, and it can even be lost on the network. > Don't we need a retry loop here too? > > > -- > Nadav Har'El > n...@scylladb.com > > On Fri, Dec 23, 2016 at 12:15 AM, Justin Cinkelj > wrote: > > > We want to propagate new hostname to DNS server via DHCP server. > > Previously, a DHCP release followed by a new DORA cycle was used. > > This did update DNS name, but VM was for a short period of time > > without a valid IP. > > > > Now an early lease renew (with the new hostname included) is sent. > > Thus VM does not need to stop using assigned IP address. > > > > Fixes #816 > > > > Signed-off-by: Justin Cinkelj > > --- > > core/dhcp.cc | 33 + > > include/osv/dhcp.hh | 4 +++- > > modules/cloud-init/cloud-init.cc | 10 +- > > 3 files changed, 37 insertions(+), 10 deletions(-) > > > > diff --git a/core/dhcp.cc b/core/dhcp.cc > > index 0436837..b0e9f1e 100644 > > --- a/core/dhcp.cc > > +++ b/core/dhcp.cc > > @@ -72,10 +72,9 @@ void dhcp_release() > > net_dhcp_worker.release(); > > } > > > > -void dhcp_restart(bool wait) > > +void dhcp_renew() > > { > > -net_dhcp_worker.release(); > > -net_dhcp_worker.start(wait); > > +net_dhcp_worker.renew(); > > } > > > > namespace dhcp { > > @@ -221,6 +220,9 @@ namespace dhcp { > > pkt->secs = 0; > > pkt->flags = 0; > > memcpy(pkt->chaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN); > > +ulong yip_n = htonl(yip.to_ulong()); > > +ulong sip_n = htonl(sip.to_ulong()); > > +memcpy(&pkt->ciaddr.s_addr, &yip_n, 4); > > > > // Options > > u8* options_start = reinterpret_cast(pkt+1); > > @@ -242,7 +244,7 @@ namespace dhcp { > > *options++ = DHCP_OPTION_END; > > > > dhcp_len += options - options_start; > > -build_udp_ip_headers(dhcp_len, INADDR_ANY, INADDR_BROADCAST); > > +build_udp_ip_headers(dhcp_len, yip_n, sip_n); > > } > > > > void dhcp_mbuf::compose_release(struct ifnet* ifp, > > @@ -541,6 +543,22 @@ namespace dhcp { > > _client_addr = _server_addr = ipv4_zero; > > } > > > > +void dhcp_interface_state::renew() > > +{ > > +// Update state > > +_state = DHCP_REQUEST; > > + > > +// Compose a dhcp request packet > > +dhcp_mbuf dm(false); > > +_xid = rand(); > > +dm.compose_request(_ifp, > > + _xid, > > + _client_addr, _server_addr); > > + > > +// Send > > +_sock->dhcp_send(dm); > > +} > > + > > void dhcp_interface_state::process_packet(struct mbuf* m) > > { > > dhcp_mbuf dm(true, m); > > @@ -724,6 +742,13 @@ namespace dhcp { > > usleep(1000); > > } > > > > +void dhcp_worker::renew() > > +{ > > +for (auto &it: _universe) { > > +it.second->renew(); > > +} > > +} > > + > > void dhcp_worker::dhcp_worker_fn() > > { > > while (true) { > > diff --git a/include/osv/dhcp.hh b/include/osv/dhcp.hh > > index b286727..166df48 100644 > > --- a/include/osv/dhcp.hh > > +++ b/include/osv/dhcp.hh > > @@ -25,7 +25,7 @@ > > extern "C" { > > void dhcp_start(bool wait); > > void dhcp_release(); > > -void dhcp_restart(bool wait); > > +void dhcp_renew(); > > } > > > > namespace dhcp { > > @@ -226,6 +226,7 @@ namespace dhcp { > > > > void discover(); > > void release(); > > +void renew(); > > void process_packet(struct mbuf*); > > void state_discover(dhcp_mbuf &dm); > > void state_request(dhcp_mbuf &dm); > > @@ -256,6 +257,7 @@ namespace dhcp { > > void start(bool wait); > > // Send release packet for all DHCP IPs. > > void release(); > > +void renew(); > > > > void dhcp_worker_fn