return false;
}
+/*
+ * Sorting of assignment entries:
+ * Primary on assignment length: smallest assignment first
+ * Secondary on assignment weight: highest weight first
+ * Finally alphabetical order of interface names
+ */
+static int prefix_assignment_cmp(const void *k1, const void *k2, void *ptr)
+{
+ const struct device_prefix_assignment *a1 = k1, *a2 = k2;
+
+ if (a1->length != a2->length)
+ return a1->length - a2->length;
+
+ if (a1->weight != a2->weight)
+ return a2->weight - a1->weight;
+
+ return strcmp(a1->name, a2->name);
+}
+
static void interface_update_prefix_assignments(struct device_prefix *prefix, bool setup)
{
struct device_prefix_assignment *c;
}
bool assigned_any = false;
- struct list_head assign_later = LIST_HEAD_INIT(assign_later);
+ struct {
+ struct avl_node node;
+ } *entry, *n_entry;
+ struct avl_tree assign_later;
+
+ avl_init(&assign_later, prefix_assignment_cmp, false, NULL);
+
vlist_for_each_element(&interfaces, iface, node) {
if (iface->assignment_length < 48 ||
iface->assignment_length > 64)
c->length = iface->assignment_length;
c->assigned = iface->assignment_hint;
+ c->weight = iface->assignment_weight;
c->addr = in6addr_any;
c->enabled = false;
memcpy(c->name, iface->name, namelen);
"of size %hhu for %s, trying other\n", c->length, c->name);
}
- struct list_head *next = &assign_later;
- struct device_prefix_assignment *n;
- list_for_each_entry(n, &assign_later, head) {
- if (n->length < c->length) {
- next = &n->head;
- break;
- }
- }
- list_add_tail(&c->head, next);
+ entry = calloc(1, sizeof(*entry));
+ if (!entry)
+ continue;
+
+ entry->node.key = c;
+ avl_insert(&assign_later, &entry->node);
}
if (c->assigned != -1)
assigned_any = true;
}
- // Then try to assign all other + failed custom assignments
- while (!list_empty(&assign_later)) {
- c = list_first_entry(&assign_later, struct device_prefix_assignment, head);
- list_del(&c->head);
-
+ /* Then try to assign all other + failed custom assignments */
+ avl_for_each_element_safe(&assign_later, entry, node, n_entry) {
bool assigned = false;
+
+ c = (struct device_prefix_assignment *)entry->node.key;
+ avl_delete(&assign_later, &entry->node);
+
do {
assigned = interface_prefix_assign(&prefix->assignments, c);
} while (!assigned && ++c->length <= 64);
netifd_log_message(L_WARNING, "Failed to assign subprefix "
"of size %hhu for %s\n", c->length, c->name);
free(c);
- } else {
+ } else
assigned_any = true;
- }
+
+ free(entry);
}
list_for_each_entry(c, &prefix->assignments, head)
IFACE_ATTR_DELEGATE,
IFACE_ATTR_IP6IFACEID,
IFACE_ATTR_FORCE_LINK,
+ IFACE_ATTR_IP6WEIGHT,
IFACE_ATTR_MAX
};
[IFACE_ATTR_DELEGATE] = { .name = "delegate", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_IP6IFACEID] = { .name = "ip6ifaceid", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_FORCE_LINK] = { .name = "force_link", .type = BLOBMSG_TYPE_BOOL },
+ [IFACE_ATTR_IP6WEIGHT] = { .name = "ip6weight", .type = BLOBMSG_TYPE_INT32 },
};
const struct uci_blob_param_list interface_attr_list = {
bool changed = (old->assignment_hint != new->assignment_hint ||
old->assignment_length != new->assignment_length ||
old->assignment_iface_id_selection != new->assignment_iface_id_selection ||
+ old->assignment_weight != new->assignment_weight ||
(old->assignment_iface_id_selection == IFID_FIXED &&
memcmp(&old->assignment_fixed_iface_id, &new->assignment_fixed_iface_id,
sizeof(old->assignment_fixed_iface_id))) ||
old->assignment_length = new->assignment_length;
old->assignment_iface_id_selection = new->assignment_iface_id_selection;
old->assignment_fixed_iface_id = new->assignment_fixed_iface_id;
+ old->assignment_weight = new->assignment_weight;
interface_refresh_assignments(true);
}
}
if ((cur = tb[IFACE_ATTR_IP6CLASS]))
interface_add_assignment_classes(iface, cur);
+ if ((cur = tb[IFACE_ATTR_IP6WEIGHT]))
+ iface->assignment_weight = blobmsg_get_u32(cur);
if ((cur = tb[IFACE_ATTR_IP4TABLE])) {
if (!system_resolve_rt_table(blobmsg_data(cur), &iface->ip4table))
blobmsg_add_u32(&b, "metric", iface->metric);
blobmsg_add_u32(&b, "dns_metric", iface->dns_metric);
blobmsg_add_u8(&b, "delegation", !iface->proto_ip.no_delegation);
+ if (iface->assignment_weight)
+ blobmsg_add_u32(&b, "ip6weight", iface->assignment_weight);
a = blobmsg_open_array(&b, "ipv4-address");
interface_ip_dump_address_list(&iface->config_ip, false, true);
interface_ip_dump_address_list(&iface->proto_ip, false, true);