+static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver,
+ void *dst, uint32_t max_start_pad,
+ uint32_t max_end_pad)
+{
+ struct netlink_client *c=sst;
+ struct netlink *st=c->nst;
+
+ if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
+ if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
+ c->deliver=deliver;
+ c->dst=dst;
+}
+
+static struct flagstr netlink_option_table[]={
+ { "soft", OPT_SOFTROUTE },
+ { "allow-route", OPT_ALLOWROUTE },
+ { NULL, 0}
+};
+/* This is the routine that gets called when the closure that's
+ returned by an invocation of a netlink device closure (eg. tun,
+ userv-ipif) is invoked. It's used to create routes and pass in
+ information about them; the closure it returns is used by site
+ code. */
+static closure_t *netlink_inst_create(struct netlink *st,
+ struct cloc loc, dict_t *dict)
+{
+ struct netlink_client *c;
+ string_t name;
+ struct subnet_list networks;
+ uint32_t options;
+
+ name=dict_read_string(dict, "name", True, st->name, loc);
+
+ dict_read_subnet_list(dict, "routes", True, st->name, loc,
+ &networks);
+ options=string_list_to_word(dict_lookup(dict,"options"),
+ netlink_option_table,st->name);
+
+ if ((options&OPT_SOFTROUTE) && !st->set_route) {
+ cfgfatal(loc,st->name,"this netlink device does not support "
+ "soft routes.\n");
+ return NULL;
+ }
+
+ if (options&OPT_SOFTROUTE) {
+ /* XXX for now we assume that soft routes require root privilege;
+ this may not always be true. The device driver can tell us. */
+ require_root_privileges=True;
+ require_root_privileges_explanation="netlink: soft routes";
+ if (st->ptp) {
+ cfgfatal(loc,st->name,"point-to-point netlinks do not support "
+ "soft routes.\n");
+ return NULL;
+ }
+ }
+
+ /* Check that nets do not intersect st->exclude_remote_networks;
+ refuse to register if they do. */
+ if (subnet_lists_intersect(&st->exclude_remote_networks,&networks)) {
+ cfgfatal(loc,st->name,"networks intersect with the explicitly "
+ "excluded remote networks\n");
+ return NULL;
+ }
+
+ c=safe_malloc(sizeof(*c),"netlink_inst_create");
+ c->cl.description=name;
+ c->cl.type=CL_NETLINK;
+ c->cl.apply=NULL;
+ c->cl.interface=&c->ops;
+ c->ops.st=c;
+ c->ops.reg=netlink_inst_reg;
+ c->ops.deliver=netlink_inst_incoming;
+ c->ops.set_quality=netlink_set_quality;
+ c->nst=st;
+
+ c->networks=networks;
+ c->deliver=NULL;
+ c->dst=NULL;
+ c->name=name;
+ c->options=options;
+ c->link_quality=LINK_QUALITY_DOWN;
+ c->next=st->clients;
+ st->clients=c;
+ st->n_routes+=networks.entries;
+
+ return &c->cl;
+}
+
+static list_t *netlink_inst_apply(closure_t *self, struct cloc loc,
+ dict_t *context, list_t *args)
+{
+ struct netlink *st=self->interface;
+
+ dict_t *dict;
+ item_t *item;
+ closure_t *cl;
+
+ Message(M_DEBUG_CONFIG,"netlink_inst_apply\n");
+
+ item=list_elem(args,0);
+ if (!item || item->type!=t_dict) {
+ cfgfatal(loc,st->name,"must have a dictionary argument\n");
+ }
+ dict=item->data.dict;
+
+ cl=netlink_inst_create(st,loc,dict);
+
+ return new_closure(cl);
+}
+