Hardware link status can 'bounce' erratically while link properties are

being updated, so perform status debouncing.

While ifch is doing work, the netlink events are ignored.  Once ifch has
finished its work, netlink events are no longer ignored.  Making this
work requires ifch to communicate back to ndhc, but it is no problem
since the necessary pipes are already in place for IPC.
This commit is contained in:
Nicholas J. Kain 2014-03-17 02:55:47 -04:00
parent d8e3dc61ea
commit 6fcc43d169
8 changed files with 72 additions and 19 deletions

View File

@ -485,7 +485,7 @@ void arp_success(struct client_state_t *cs)
cs->init = 0;
last_conflict_ts = 0;
arp_wake_ts[AS_COLLISION_CHECK] = -1;
ifchange_bind(&arp_dhcp_packet);
ifchange_bind(cs, &arp_dhcp_packet);
if (cs->arpPrevState == DS_RENEWING || cs->arpPrevState == DS_REBINDING) {
arp_switch_state(cs, AS_DEFENSE);
} else {

View File

@ -45,7 +45,6 @@
#include "ifchange.h"
#include "ifch_proto.h"
static int cfg_deconfig; // Set if the interface has already been deconfigured.
static struct dhcpmsg cfg_packet; // Copy of the current configuration packet.
static int ifchd_cmd_u8(char *buf, size_t buflen, char *optname,
@ -155,8 +154,9 @@ static int ifchd_cmd(char *buf, size_t buflen, uint8_t *optdata,
}
#undef IFCHD_SW_CMD
static void pipewrite(const char *buf, size_t count)
static void pipewrite(struct client_state_t *cs, const char *buf, size_t count)
{
cs->ifchWorking = 1;
if (safe_write(pToIfchW, buf, count) == -1) {
log_error("pipewrite: write failed: %s", strerror(errno));
return;
@ -164,18 +164,18 @@ static void pipewrite(const char *buf, size_t count)
log_line("Sent to ifchd: %s", buf);
}
void ifchange_deconfig(void)
void ifchange_deconfig(struct client_state_t *cs)
{
char buf[256];
if (cfg_deconfig)
if (cs->ifDeconfig)
return;
cs->ifDeconfig = 1;
snprintf(buf, sizeof buf, "ip4:0.0.0.0,255.255.255.255;");
log_line("Resetting %s IP configuration.", client_config.interface);
pipewrite(buf, strlen(buf));
pipewrite(cs, buf, strlen(buf));
cfg_deconfig = 1;
memset(&cfg_packet, 0, sizeof cfg_packet);
}
@ -258,7 +258,7 @@ static size_t send_cmd(char *out, size_t olen, struct dhcpmsg *packet,
return strlen(buf);
}
void ifchange_bind(struct dhcpmsg *packet)
void ifchange_bind(struct client_state_t *cs, struct dhcpmsg *packet)
{
char buf[2048];
int tbs = 0;
@ -275,8 +275,8 @@ void ifchange_bind(struct dhcpmsg *packet)
tbs |= send_cmd(buf, sizeof buf, packet, DCODE_MTU);
tbs |= send_cmd(buf, sizeof buf, packet, DCODE_WINS);
if (tbs)
pipewrite(buf, strlen(buf));
pipewrite(cs, buf, strlen(buf));
cfg_deconfig = 0;
cs->ifDeconfig = 0;
memcpy(&cfg_packet, packet, sizeof cfg_packet);
}

View File

@ -29,7 +29,7 @@
#ifndef IFCHANGE_H_
#define IFCHANGE_H_
void ifchange_bind(struct dhcpmsg *packet);
void ifchange_deconfig(void);
void ifchange_bind(struct client_state_t *cs, struct dhcpmsg *packet);
void ifchange_deconfig(struct client_state_t *cs);
#endif

View File

@ -303,6 +303,24 @@ static void signal_dispatch(void)
}
}
static void inform_execute(int success)
{
int r;
char c = success ? '+' : '-';
retry:
r = safe_write(pToNdhcW, &c, sizeof c);
if (r == 0) {
// Remote end hung up.
exit(EXIT_SUCCESS);
} else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
goto retry;
log_line("%s: (%s) error writing to ifch -> ndhc pipe: %s",
client_config.interface, __func__, strerror(errno));
exit(EXIT_FAILURE);
}
}
static void process_client_pipe(void)
{
char buf[MAX_BUF];
@ -315,14 +333,18 @@ static void process_client_pipe(void)
} else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return;
log_line("ifch: error reading from ndhc -> ifch pipe: %s", strerror(errno));
log_line("%s: (%s) error reading from ndhc -> ifch pipe: %s",
client_config.interface, __func__, strerror(errno));
exit(EXIT_FAILURE);
}
if (execute_buffer(buf) == -1) {
log_line("ifch: execute_buffer was passed invalid commands: '%s'", buf);
log_line("%s: (%s) execute_buffer was passed invalid commands: '%s'",
client_config.interface, __func__, buf);
inform_execute(0);
exit(EXIT_FAILURE);
}
} else
inform_execute(1);
}
void do_ifch_work(void)

View File

@ -71,6 +71,8 @@
#include "ifchd.h"
struct client_state_t cs = {
.ifchWorking = 0,
.ifDeconfig = 0,
.init = 1,
.epollFd = -1,
.signalFd = -1,
@ -213,9 +215,29 @@ static int get_clientid_mac_string(char *str, size_t slen)
return 1;
}
static void handle_ifch_message(void)
{
char c;
int r = safe_read(pToNdhcR, &c, sizeof c);
if (r == 0) {
// Remote end hung up.
exit(EXIT_SUCCESS);
} else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return;
log_line("%s: (%s) error reading from ifch -> ndhc pipe: %s",
client_config.interface, __func__, strerror(errno));
exit(EXIT_FAILURE);
}
if (c == '+')
cs.ifchWorking = 0;
}
#define NDHC_NUM_EP_FDS 4
static void do_ndhc_work(void)
{
struct epoll_event events[3];
struct epoll_event events[NDHC_NUM_EP_FDS];
long long nowts;
int timeout;
@ -229,12 +251,13 @@ static void do_ndhc_work(void)
setup_signals_ndhc();
epoll_add(cs.epollFd, cs.nlFd);
epoll_add(cs.epollFd, pToNdhcR);
set_listen_raw(&cs);
nowts = curms();
goto jumpstart;
for (;;) {
int r = epoll_wait(cs.epollFd, events, 3, timeout);
int r = epoll_wait(cs.epollFd, events, NDHC_NUM_EP_FDS, timeout);
if (r == -1) {
if (errno == EINTR)
continue;
@ -251,6 +274,8 @@ static void do_ndhc_work(void)
handle_arp_response(&cs);
else if (fd == cs.nlFd)
handle_nl_message(&cs);
else if (fd == pToNdhcR)
handle_ifch_message();
else
suicide("epoll_wait: unknown fd");
}
@ -336,7 +361,7 @@ static void ndhc_main(void) {
drop_root(ndhc_uid, ndhc_gid);
if (cs.ifsPrevState != IFS_UP)
ifchange_deconfig();
ifchange_deconfig(&cs);
do_ndhc_work();
}

View File

@ -38,6 +38,8 @@ struct client_state_t {
int dhcpState;
int arpPrevState;
int ifsPrevState;
int ifchWorking; // ifch is performing interface changes.
int ifDeconfig; // Set if the interface has already been deconfigured.
int listenMode;
int epollFd, signalFd, listenFd, arpFd, nlFd;
int nlPortId;

View File

@ -89,6 +89,8 @@ static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
get_if_index_and_mac(nlh, ifm);
if (ifm->ifi_index != client_config.ifindex)
break;
if (cs->ifchWorking)
break;
// IFF_UP corresponds to ifconfig down or ifconfig up.
if (ifm->ifi_flags & IFF_UP) {
// IFF_RUNNING is the hardware carrier.
@ -111,6 +113,8 @@ static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
case RTM_DELLINK:
if (ifm->ifi_index != client_config.ifindex)
break;
if (cs->ifchWorking)
break;
if (cs->ifsPrevState != IFS_REMOVED) {
cs->ifsPrevState = IFS_REMOVED;
log_line("Interface removed. Exiting.");

View File

@ -88,7 +88,7 @@ static int delay_timeout(size_t numpackets)
static void reinit_shared_deconfig(struct client_state_t *cs)
{
ifchange_deconfig();
ifchange_deconfig(cs);
arp_close_fd(cs);
cs->clientAddr = 0;
num_dhcp_requests = 0;