From 31eb441db163bf4965c940792f0675c2508a5cff Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 21 Apr 2019 18:08:18 +0200 Subject: [PATCH] respondd: make delays specific for group and interface Previously, delays were specific for interfaces, but not for the group address. This behaviour was confusing when the same interface was passed for multiple group addresses. Fix by keeping track of both groups and interfaces. --- net/respondd/src/respondd.c | 95 ++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/net/respondd/src/respondd.c b/net/respondd/src/respondd.c index e67ee41..11391ed 100644 --- a/net/respondd/src/respondd.c +++ b/net/respondd/src/respondd.c @@ -57,13 +57,20 @@ #define REQUEST_MAXLEN 256 #define MAX_MULTICAST_DELAY_DEFAULT 0 -struct interface_delay_info { - struct interface_delay_info *next; +struct interface_info { + struct interface_info *next; unsigned int ifindex; uint64_t max_multicast_delay; }; +struct group_info { + struct group_info *next; + struct in6_addr address; + + struct interface_info *interfaces; +}; + struct provider_list { struct provider_list *next; @@ -496,6 +503,22 @@ void serve_request(struct request_task *task, int sock) { ); } +static const struct interface_info * find_multicast_interface(const struct group_info *groups, unsigned ifindex, const struct in6_addr *addr) { + for (const struct group_info *group = groups; group; group = group->next) { + if (memcmp(addr, &group->address, sizeof(struct in6_addr)) != 0) + continue; + + for (const struct interface_info *iface = group->interfaces; iface; iface = iface->next) { + if (ifindex != iface->ifindex) + continue; + + return iface; + } + } + + return NULL; +} + /** * Wait for an incoming request and schedule it. * @@ -515,7 +538,7 @@ void serve_request(struct request_task *task, int sock) { * will be also sent immediately. */ static void accept_request(struct request_schedule *schedule, int sock, - struct interface_delay_info *if_delay_info_list) { + const struct group_info *groups) { char input[REQUEST_MAXLEN]; ssize_t input_bytes; struct sockaddr_in6 addr; @@ -580,30 +603,29 @@ static void accept_request(struct request_schedule *schedule, int sock, input[input_bytes] = 0; - // get the max delay - uint64_t max_multicast_delay = MAX_MULTICAST_DELAY_DEFAULT; - struct interface_delay_info *tmp = if_delay_info_list; - for (; tmp; tmp = tmp->next) { - if (tmp->ifindex == ifindex) { - max_multicast_delay = tmp->max_multicast_delay; - break; - } + const struct interface_info *iface = NULL; + if (IN6_IS_ADDR_MULTICAST(&destaddr)) { + iface = find_multicast_interface(groups, ifindex, &destaddr); + // this should not happen + if (!iface) + return; } struct request_task *new_task = malloc(sizeof(*new_task)); - // the ternary operator avoids division by 0 - new_task->scheduled_time = max_multicast_delay ? now + rand() % max_multicast_delay : 0; + new_task->scheduled_time = 0; strncpy(new_task->request, input, input_bytes + 1); new_task->request[input_bytes] = 0; new_task->client_addr = addr; bool is_scheduled; - if(new_task->scheduled_time && IN6_IS_ADDR_MULTICAST(&destaddr)) + if (iface) { // scheduling could fail because the schedule is full + new_task->scheduled_time = now + rand() % iface->max_multicast_delay; is_scheduled = schedule_push_request(schedule, new_task); - else + } else { // unicast packets are always sent directly is_scheduled = false; + } if (!is_scheduled) { // reply immediately @@ -650,10 +672,7 @@ int main(int argc, char **argv) { char *endptr; opterr = 0; - int group_set = 0; - bool iface_set = false; - unsigned int last_ifindex = 0; - struct interface_delay_info *if_delay_info_list = NULL; + struct group_info *groups = NULL; openlog("respondd", LOG_PID, LOG_DAEMON); @@ -670,24 +689,34 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - group_set = 1; + struct group_info *new_group = malloc(sizeof(*new_group)); + new_group->address = mgroup_addr; + new_group->interfaces = NULL; + new_group->next = groups; + groups = new_group; break; case 'i': - if (!group_set) { + if (!groups) { fprintf(stderr, "Multicast group must be given before interface.\n"); exit(EXIT_FAILURE); } - iface_set = true; - last_ifindex = if_nametoindex(optarg); - if(!join_mcast(sock, mgroup_addr, last_ifindex)) { + int ifindex = if_nametoindex(optarg); + if (!join_mcast(sock, mgroup_addr, ifindex)) { fprintf(stderr, "Could not join multicast group on %s: ", optarg); - last_ifindex = 0; + continue; } + + struct interface_info *new_iface = malloc(sizeof(*new_iface)); + new_iface->ifindex = ifindex; + new_iface->max_multicast_delay = MAX_MULTICAST_DELAY_DEFAULT; + new_iface->next = groups->interfaces; + groups->interfaces = new_iface; + break; case 't': - if (!iface_set) { + if (!groups || !groups->interfaces) { fprintf(stderr, "Interface must be given before max response delay.\n"); exit(EXIT_FAILURE); } @@ -698,17 +727,7 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - if (last_ifindex) { - // insert the interface delay info at the beginning of the list - struct interface_delay_info **head = &if_delay_info_list; - struct interface_delay_info *old_head = if_delay_info_list; - - *head = malloc(sizeof(*if_delay_info_list)); - (*head)->ifindex = last_ifindex; - (*head)->max_multicast_delay = max_multicast_delay; - (*head)->next = old_head; - } - + groups->interfaces->max_multicast_delay = max_multicast_delay; break; @@ -734,7 +753,7 @@ int main(int argc, char **argv) { struct request_schedule schedule = {}; while (true) { - accept_request(&schedule, sock, if_delay_info_list); + accept_request(&schedule, sock, groups); struct request_task *task = schedule_pop_request(&schedule);