ipv6: sr: implement API to control SR HMAC structure
This patch provides an implementation of the genetlink commands to associate a given HMAC key identifier with an hashing algorithm and a secret. Signed-off-by: David Lebrun <david.lebrun@uclouvain.be> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bf355b8d2c
commit
4f4853dc1c
1 changed files with 229 additions and 0 deletions
229
net/ipv6/seg6.c
229
net/ipv6/seg6.c
|
@ -25,6 +25,9 @@
|
||||||
#include <net/genetlink.h>
|
#include <net/genetlink.h>
|
||||||
#include <linux/seg6.h>
|
#include <linux/seg6.h>
|
||||||
#include <linux/seg6_genl.h>
|
#include <linux/seg6_genl.h>
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
#include <net/seg6_hmac.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
|
bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
|
||||||
{
|
{
|
||||||
|
@ -76,11 +79,90 @@ static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
|
||||||
[SEG6_ATTR_HMACINFO] = { .type = NLA_NESTED, },
|
[SEG6_ATTR_HMACINFO] = { .type = NLA_NESTED, },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
|
||||||
|
static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
{
|
||||||
|
struct net *net = genl_info_net(info);
|
||||||
|
struct seg6_pernet_data *sdata;
|
||||||
|
struct seg6_hmac_info *hinfo;
|
||||||
|
u32 hmackeyid;
|
||||||
|
char *secret;
|
||||||
|
int err = 0;
|
||||||
|
u8 algid;
|
||||||
|
u8 slen;
|
||||||
|
|
||||||
|
sdata = seg6_pernet(net);
|
||||||
|
|
||||||
|
if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
|
||||||
|
!info->attrs[SEG6_ATTR_SECRETLEN] ||
|
||||||
|
!info->attrs[SEG6_ATTR_ALGID])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
|
||||||
|
slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
|
||||||
|
algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
|
||||||
|
|
||||||
|
if (hmackeyid == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (slen > SEG6_HMAC_SECRET_LEN)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&sdata->lock);
|
||||||
|
hinfo = seg6_hmac_info_lookup(net, hmackeyid);
|
||||||
|
|
||||||
|
if (!slen) {
|
||||||
|
if (!hinfo)
|
||||||
|
err = -ENOENT;
|
||||||
|
|
||||||
|
err = seg6_hmac_info_del(net, hmackeyid);
|
||||||
|
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->attrs[SEG6_ATTR_SECRET]) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hinfo) {
|
||||||
|
err = seg6_hmac_info_del(net, hmackeyid);
|
||||||
|
if (err)
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
|
||||||
|
|
||||||
|
hinfo = kzalloc(sizeof(*hinfo), GFP_KERNEL);
|
||||||
|
if (!hinfo) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(hinfo->secret, secret, slen);
|
||||||
|
hinfo->slen = slen;
|
||||||
|
hinfo->alg_id = algid;
|
||||||
|
hinfo->hmackeyid = hmackeyid;
|
||||||
|
|
||||||
|
err = seg6_hmac_info_add(net, hmackeyid, hinfo);
|
||||||
|
if (err)
|
||||||
|
kfree(hinfo);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&sdata->lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
|
static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
|
static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct net *net = genl_info_net(info);
|
struct net *net = genl_info_net(info);
|
||||||
|
@ -145,11 +227,135 @@ free_msg:
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
|
||||||
|
static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
|
||||||
|
struct sk_buff *msg)
|
||||||
|
{
|
||||||
|
if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
|
||||||
|
nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
|
||||||
|
nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
|
||||||
|
nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
|
||||||
|
u32 portid, u32 seq, u32 flags,
|
||||||
|
struct sk_buff *skb, u8 cmd)
|
||||||
|
{
|
||||||
|
void *hdr;
|
||||||
|
|
||||||
|
hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
|
||||||
|
if (!hdr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (__seg6_hmac_fill_info(hinfo, skb) < 0)
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
genlmsg_end(skb, hdr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
genlmsg_cancel(skb, hdr);
|
||||||
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
struct net *net = sock_net(cb->skb->sk);
|
||||||
|
struct seg6_pernet_data *sdata;
|
||||||
|
struct rhashtable_iter *iter;
|
||||||
|
|
||||||
|
sdata = seg6_pernet(net);
|
||||||
|
iter = (struct rhashtable_iter *)cb->args[0];
|
||||||
|
|
||||||
|
if (!iter) {
|
||||||
|
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
|
||||||
|
if (!iter)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cb->args[0] = (long)iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
rhashtable_walk_enter(&sdata->hmac_infos, iter);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
|
||||||
|
|
||||||
|
rhashtable_walk_exit(iter);
|
||||||
|
|
||||||
|
kfree(iter);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
|
||||||
|
struct net *net = sock_net(skb->sk);
|
||||||
|
struct seg6_pernet_data *sdata;
|
||||||
|
struct seg6_hmac_info *hinfo;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sdata = seg6_pernet(net);
|
||||||
|
|
||||||
|
ret = rhashtable_walk_start(iter);
|
||||||
|
if (ret && ret != -EAGAIN)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
hinfo = rhashtable_walk_next(iter);
|
||||||
|
|
||||||
|
if (IS_ERR(hinfo)) {
|
||||||
|
if (PTR_ERR(hinfo) == -EAGAIN)
|
||||||
|
continue;
|
||||||
|
ret = PTR_ERR(hinfo);
|
||||||
|
goto done;
|
||||||
|
} else if (!hinfo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = __seg6_genl_dumphmac_element(hinfo,
|
||||||
|
NETLINK_CB(cb->skb).portid,
|
||||||
|
cb->nlh->nlmsg_seq,
|
||||||
|
NLM_F_MULTI,
|
||||||
|
skb, SEG6_CMD_DUMPHMAC);
|
||||||
|
if (ret)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = skb->len;
|
||||||
|
|
||||||
|
done:
|
||||||
|
rhashtable_walk_stop(iter);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
|
static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __net_init seg6_net_init(struct net *net)
|
static int __net_init seg6_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
struct seg6_pernet_data *sdata;
|
struct seg6_pernet_data *sdata;
|
||||||
|
@ -168,6 +374,10 @@ static int __net_init seg6_net_init(struct net *net)
|
||||||
|
|
||||||
net->ipv6.seg6_data = sdata;
|
net->ipv6.seg6_data = sdata;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
seg6_hmac_net_init(net);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +385,10 @@ static void __net_exit seg6_net_exit(struct net *net)
|
||||||
{
|
{
|
||||||
struct seg6_pernet_data *sdata = seg6_pernet(net);
|
struct seg6_pernet_data *sdata = seg6_pernet(net);
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
seg6_hmac_net_exit(net);
|
||||||
|
#endif
|
||||||
|
|
||||||
kfree(sdata->tun_src);
|
kfree(sdata->tun_src);
|
||||||
kfree(sdata);
|
kfree(sdata);
|
||||||
}
|
}
|
||||||
|
@ -193,7 +407,9 @@ static const struct genl_ops seg6_genl_ops[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.cmd = SEG6_CMD_DUMPHMAC,
|
.cmd = SEG6_CMD_DUMPHMAC,
|
||||||
|
.start = seg6_genl_dumphmac_start,
|
||||||
.dumpit = seg6_genl_dumphmac,
|
.dumpit = seg6_genl_dumphmac,
|
||||||
|
.done = seg6_genl_dumphmac_done,
|
||||||
.policy = seg6_genl_policy,
|
.policy = seg6_genl_policy,
|
||||||
.flags = GENL_ADMIN_PERM,
|
.flags = GENL_ADMIN_PERM,
|
||||||
},
|
},
|
||||||
|
@ -239,10 +455,20 @@ int __init seg6_init(void)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_unregister_pernet;
|
goto out_unregister_pernet;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
err = seg6_hmac_init();
|
||||||
|
if (err)
|
||||||
|
goto out_unregister_iptun;
|
||||||
|
#endif
|
||||||
|
|
||||||
pr_info("Segment Routing with IPv6\n");
|
pr_info("Segment Routing with IPv6\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
out_unregister_iptun:
|
||||||
|
seg6_iptunnel_exit();
|
||||||
|
#endif
|
||||||
out_unregister_pernet:
|
out_unregister_pernet:
|
||||||
unregister_pernet_subsys(&ip6_segments_ops);
|
unregister_pernet_subsys(&ip6_segments_ops);
|
||||||
out_unregister_genl:
|
out_unregister_genl:
|
||||||
|
@ -252,6 +478,9 @@ out_unregister_genl:
|
||||||
|
|
||||||
void seg6_exit(void)
|
void seg6_exit(void)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||||
|
seg6_hmac_exit();
|
||||||
|
#endif
|
||||||
seg6_iptunnel_exit();
|
seg6_iptunnel_exit();
|
||||||
unregister_pernet_subsys(&ip6_segments_ops);
|
unregister_pernet_subsys(&ip6_segments_ops);
|
||||||
genl_unregister_family(&seg6_genl_family);
|
genl_unregister_family(&seg6_genl_family);
|
||||||
|
|
Loading…
Add table
Reference in a new issue