if (info->attrs[ILA_ATTR_IFINDEX])
xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
return 0;
}
/* Must be called with rcu readlock */ staticinlinestruct ila_map *ila_lookup_wildcards(struct ila_addr *iaddr, int ifindex, struct ila_net *ilan)
{ struct ila_map *ila;
ila = rhashtable_lookup_fast(&ilan->xlat.rhash_table, &iaddr->loc,
rht_params); while (ila) { if (!ila_cmp_wildcards(ila, iaddr, ifindex)) return ila;
ila = rcu_access_pointer(ila->next);
}
return NULL;
}
/* Must be called with rcu readlock */ staticinlinestruct ila_map *ila_lookup_by_params(struct ila_xlat_params *xp, struct ila_net *ilan)
{ struct ila_map *ila;
ila = rhashtable_lookup_fast(&ilan->xlat.rhash_table,
&xp->ip.locator_match,
rht_params); while (ila) { if (!ila_cmp_params(ila, xp)) return ila;
ila = rcu_access_pointer(ila->next);
}
if (!READ_ONCE(ilan->xlat.hooks_registered)) { /* We defer registering net hooks in the namespace until the * first mapping is added.
*/
mutex_lock(&ila_mutex); if (!ilan->xlat.hooks_registered) {
err = nf_register_net_hooks(net, ila_nf_hook_ops,
ARRAY_SIZE(ila_nf_hook_ops)); if (!err)
WRITE_ONCE(ilan->xlat.hooks_registered, true);
}
mutex_unlock(&ila_mutex); if (err) return err;
}
ila = kzalloc(sizeof(*ila), GFP_KERNEL); if (!ila) return -ENOMEM;
ila_init_saved_csum(&xp->ip);
ila->xp = *xp;
order = ila_order(ila);
spin_lock(lock);
head = rhashtable_lookup_fast(&ilan->xlat.rhash_table,
&xp->ip.locator_match,
rht_params); if (!head) { /* New entry for the rhash_table */
err = rhashtable_lookup_insert_fast(&ilan->xlat.rhash_table,
&ila->node, rht_params);
} else { struct ila_map *tila = head, *prev = NULL;
do { if (!ila_cmp_params(tila, xp)) {
err = -EEXIST; goto out;
}
if (order > ila_order(tila)) break;
prev = tila;
tila = rcu_dereference_protected(tila->next,
lockdep_is_held(lock));
} while (tila);
if (prev) { /* Insert in sub list of head */
RCU_INIT_POINTER(ila->next, tila);
rcu_assign_pointer(prev->next, ila);
} else { /* Make this ila new head */
RCU_INIT_POINTER(ila->next, head);
err = rhashtable_replace_fast(&ilan->xlat.rhash_table,
&head->node,
&ila->node, rht_params); if (err) goto out;
}
}
head = rhashtable_lookup_fast(&ilan->xlat.rhash_table,
&xp->ip.locator_match, rht_params);
ila = head;
prev = NULL;
while (ila) { if (ila_cmp_params(ila, xp)) {
prev = ila;
ila = rcu_dereference_protected(ila->next,
lockdep_is_held(lock)); continue;
}
err = 0;
if (prev) { /* Not head, just delete from list */
rcu_assign_pointer(prev->next, ila->next);
} else { /* It is the head. If there is something in the * sublist we need to make a new head.
*/
head = rcu_dereference_protected(ila->next,
lockdep_is_held(lock)); if (head) { /* Put first entry in the sublist into the * table
*/
err = rhashtable_replace_fast(
&ilan->xlat.rhash_table, &ila->node,
&head->node, rht_params); if (err) goto out;
} else { /* Entry no longer used */
err = rhashtable_remove_fast(
&ilan->xlat.rhash_table,
&ila->node, rht_params);
}
}
ila_release(ila);
break;
}
out:
spin_unlock(lock);
return err;
}
int ila_xlat_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
{ struct net *net = genl_info_net(info); struct ila_xlat_params p; int err;
err = parse_nl_config(info, &p); if (err) return err;
return ila_add_mapping(net, &p);
}
int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
{ struct net *net = genl_info_net(info); struct ila_xlat_params xp; int err;
err = parse_nl_config(info, &xp); if (err) return err;
int ila_xlat_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
{ struct net *net = genl_info_net(info); struct ila_net *ilan = net_generic(net, ila_net_id); struct sk_buff *msg; struct ila_xlat_params xp; struct ila_map *ila; int ret;
ret = parse_nl_config(info, &xp); if (ret) return ret;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM;
rcu_read_lock();
ret = -ESRCH;
ila = ila_lookup_by_params(&xp, ilan); if (ila) {
ret = ila_dump_info(ila,
info->snd_portid,
info->snd_seq, 0, msg,
info->genlhdr->cmd);
}
rcu_read_unlock();
if (ret < 0) goto out_free;
return genlmsg_reply(msg, info);
out_free:
nlmsg_free(msg); return ret;
}
struct ila_dump_iter { struct rhashtable_iter rhiter; int skip;
};
int ila_xlat_nl_dump_start(struct netlink_callback *cb)
{ struct net *net = sock_net(cb->skb->sk); struct ila_net *ilan = net_generic(net, ila_net_id); struct ila_dump_iter *iter;
iter = kmalloc(sizeof(*iter), GFP_KERNEL); if (!iter) return -ENOMEM;
int ila_xlat_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
{ struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0]; struct rhashtable_iter *rhiter = &iter->rhiter; int skip = iter->skip; struct ila_map *ila; int ret;
rhashtable_walk_start(rhiter);
/* Get first entry */
ila = rhashtable_walk_peek(rhiter);
if (ila && !IS_ERR(ila) && skip) { /* Skip over visited entries */
while (ila && skip) { /* Skip over any ila entries in this list that we * have already dumped.
*/
ila = rcu_access_pointer(ila->next);
skip--;
}
}
skip = 0;
for (;;) { if (IS_ERR(ila)) {
ret = PTR_ERR(ila); if (ret == -EAGAIN) { /* Table has changed and iter has reset. Return * -EAGAIN to the application even if we have * written data to the skb. The application * needs to deal with this.
*/
/* Assumes skb contains a valid IPv6 header that is pulled */
/* No check here that ILA type in the mapping matches what is in the * address. We assume that whatever sender gaves us can be translated. * The checksum mode however is relevant.
*/
rcu_read_lock();
ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan); if (ila)
ila_update_ipv6_locator(skb, &ila->xp.ip, sir2ila);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.