ROUTE_SOURCE,
ROUTE_ONLINK,
ROUTE_TYPE,
+ ROUTE_PROTO,
__ROUTE_MAX
};
[ROUTE_VALID] = { .name = "valid", .type = BLOBMSG_TYPE_INT32 },
[ROUTE_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_STRING },
[ROUTE_ONLINK] = { .name = "onlink", .type = BLOBMSG_TYPE_BOOL },
- [ROUTE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }
+ [ROUTE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
+ [ROUTE_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
};
const struct uci_blob_param_list route_attr_list = {
route->flags |= DEVROUTE_TYPE;
}
+ if ((cur = tb[ROUTE_PROTO]) != NULL) {
+ if (!system_resolve_rt_proto(blobmsg_data(cur), &route->proto)) {
+ DPRINTF("Failed to resolve proto type: %s\n", (char *) blobmsg_data(cur));
+ goto error;
+ }
+ route->flags |= DEVROUTE_PROTO;
+ }
+
interface_set_route_info(iface, route);
vlist_add(&ip->route, &route->node, route);
return;
memcpy(&r->addr, &addr->addr, sizeof(r->addr));
clear_if_addr(&r->addr, r->mask);
- r->flags |= DEVADDR_KERNEL;
+ if (!system_resolve_rt_proto("kernel", &r->proto))
+ return;
+
+ r->flags |= DEVROUTE_PROTO;
system_del_route(dev, r);
- r->flags &= ~DEVADDR_KERNEL;
+ r->flags &= ~DEVROUTE_PROTO;
interface_set_route_info(iface, r);
system_add_route(dev, r);
if (node_old && node_new)
keep = !memcmp(&route_old->nexthop, &route_new->nexthop, sizeof(route_old->nexthop)) &&
(route_old->mtu == route_new->mtu) && (route_old->type == route_new->type) &&
- !route_old->failed;
+ (route_old->proto == route_new->proto) && !route_old->failed;
if (node_old) {
if (!(route_old->flags & DEVADDR_EXTERNAL) && route_old->enabled && !keep)
}
}
-void
-interface_write_resolv_conf(void)
+/* Sorting of interface resolver entries : */
+/* Primary on interface dns_metric : lowest metric first */
+/* Secondary on interface metric : lowest metric first */
+/* Finally alphabetical order of interface names */
+static int resolv_conf_iface_cmp(const void *k1, const void *k2, void *ptr)
+{
+ const struct interface *iface1 = k1, *iface2 = k2;
+
+ if (iface1->dns_metric != iface2->dns_metric)
+ return iface1->dns_metric - iface2->dns_metric;
+
+ if (iface1->metric != iface2->metric)
+ return iface1->metric - iface2->metric;
+
+ return strcmp(iface1->name, iface2->name);
+}
+
+static void
+__interface_write_dns_entries(FILE *f)
{
struct interface *iface;
- char *path = alloca(strlen(resolv_conf) + 5);
- FILE *f;
- uint32_t crcold, crcnew;
+ struct {
+ struct avl_node node;
+ } *entry, *n_entry;
+ struct avl_tree resolv_conf_iface_entries;
- sprintf(path, "%s.tmp", resolv_conf);
- unlink(path);
- f = fopen(path, "w+");
- if (!f) {
- D(INTERFACE, "Failed to open %s for writing\n", path);
- return;
- }
+ avl_init(&resolv_conf_iface_entries, resolv_conf_iface_cmp, false, NULL);
vlist_for_each_element(&interfaces, iface, node) {
if (iface->state != IFS_UP)
if (vlist_simple_empty(&iface->proto_ip.dns_search) &&
vlist_simple_empty(&iface->proto_ip.dns_servers) &&
- vlist_simple_empty(&iface->config_ip.dns_search) &&
+ vlist_simple_empty(&iface->config_ip.dns_search) &&
vlist_simple_empty(&iface->config_ip.dns_servers))
continue;
+ entry = calloc(1, sizeof(*entry));
+ if (!entry)
+ continue;
+
+ entry->node.key = iface;
+ avl_insert(&resolv_conf_iface_entries, &entry->node);
+ }
+
+ avl_for_each_element(&resolv_conf_iface_entries, entry, node) {
+ iface = (struct interface *)entry->node.key;
+
fprintf(f, "# Interface %s\n", iface->name);
+
write_resolv_conf_entries(f, &iface->config_ip, iface->ifname);
+
if (!iface->proto_ip.no_dns)
write_resolv_conf_entries(f, &iface->proto_ip, iface->ifname);
}
+
+ avl_remove_all_elements(&resolv_conf_iface_entries, entry, node, n_entry)
+ free(entry);
+}
+
+void
+interface_write_resolv_conf(void)
+{
+ char *path = alloca(strlen(resolv_conf) + 5);
+ FILE *f;
+ uint32_t crcold, crcnew;
+
+ sprintf(path, "%s.tmp", resolv_conf);
+ unlink(path);
+ f = fopen(path, "w+");
+ if (!f) {
+ D(INTERFACE, "Failed to open %s for writing\n", path);
+ return;
+ }
+
+ __interface_write_dns_entries(f);
+
fflush(f);
rewind(f);
crcnew = crc32_file(f);