|
@@ -145,22 +145,10 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-__le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
|
|
|
+static int dn_fib_count_nhs(const struct nlattr *attr)
|
|
|
{
|
|
|
- while(RTA_OK(attr,attrlen)) {
|
|
|
- if (attr->rta_type == type)
|
|
|
- return *(__le16*)RTA_DATA(attr);
|
|
|
- attr = RTA_NEXT(attr, attrlen);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int dn_fib_count_nhs(struct rtattr *rta)
|
|
|
-{
|
|
|
- int nhs = 0;
|
|
|
- struct rtnexthop *nhp = RTA_DATA(rta);
|
|
|
- int nhlen = RTA_PAYLOAD(rta);
|
|
|
+ struct rtnexthop *nhp = nla_data(attr);
|
|
|
+ int nhs = 0, nhlen = nla_len(attr);
|
|
|
|
|
|
while(nhlen >= (int)sizeof(struct rtnexthop)) {
|
|
|
if ((nhlen -= nhp->rtnh_len) < 0)
|
|
@@ -172,10 +160,11 @@ static int dn_fib_count_nhs(struct rtattr *rta)
|
|
|
return nhs;
|
|
|
}
|
|
|
|
|
|
-static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
|
|
|
+static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
|
|
|
+ const struct rtmsg *r)
|
|
|
{
|
|
|
- struct rtnexthop *nhp = RTA_DATA(rta);
|
|
|
- int nhlen = RTA_PAYLOAD(rta);
|
|
|
+ struct rtnexthop *nhp = nla_data(attr);
|
|
|
+ int nhlen = nla_len(attr);
|
|
|
|
|
|
change_nexthops(fi) {
|
|
|
int attrlen = nhlen - sizeof(struct rtnexthop);
|
|
@@ -187,7 +176,10 @@ static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, cons
|
|
|
nh->nh_weight = nhp->rtnh_hops + 1;
|
|
|
|
|
|
if (attrlen) {
|
|
|
- nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
|
|
|
+ struct nlattr *gw_attr;
|
|
|
+
|
|
|
+ gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
|
|
|
+ nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
|
|
|
}
|
|
|
nhp = RTNH_NEXT(nhp);
|
|
|
} endfor_nexthops(fi);
|
|
@@ -268,7 +260,8 @@ out:
|
|
|
}
|
|
|
|
|
|
|
|
|
-struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
|
|
|
+struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
|
|
|
+ const struct nlmsghdr *nlh, int *errp)
|
|
|
{
|
|
|
int err;
|
|
|
struct dn_fib_info *fi = NULL;
|
|
@@ -281,11 +274,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
|
|
|
if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
|
|
|
goto err_inval;
|
|
|
|
|
|
- if (rta->rta_mp) {
|
|
|
- nhs = dn_fib_count_nhs(rta->rta_mp);
|
|
|
- if (nhs == 0)
|
|
|
- goto err_inval;
|
|
|
- }
|
|
|
+ if (attrs[RTA_MULTIPATH] &&
|
|
|
+ (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
|
|
|
+ goto err_inval;
|
|
|
|
|
|
fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
|
|
|
err = -ENOBUFS;
|
|
@@ -295,53 +286,65 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
|
|
|
fi->fib_protocol = r->rtm_protocol;
|
|
|
fi->fib_nhs = nhs;
|
|
|
fi->fib_flags = r->rtm_flags;
|
|
|
- if (rta->rta_priority)
|
|
|
- fi->fib_priority = *rta->rta_priority;
|
|
|
- if (rta->rta_mx) {
|
|
|
- int attrlen = RTA_PAYLOAD(rta->rta_mx);
|
|
|
- struct rtattr *attr = RTA_DATA(rta->rta_mx);
|
|
|
|
|
|
- while(RTA_OK(attr, attrlen)) {
|
|
|
- unsigned int flavour = attr->rta_type;
|
|
|
+ if (attrs[RTA_PRIORITY])
|
|
|
+ fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
|
|
|
+
|
|
|
+ if (attrs[RTA_METRICS]) {
|
|
|
+ struct nlattr *attr;
|
|
|
+ int rem;
|
|
|
|
|
|
- if (flavour) {
|
|
|
- if (flavour > RTAX_MAX)
|
|
|
+ nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
|
|
|
+ int type = nla_type(attr);
|
|
|
+
|
|
|
+ if (type) {
|
|
|
+ if (type > RTAX_MAX || nla_len(attr) < 4)
|
|
|
goto err_inval;
|
|
|
- fi->fib_metrics[flavour-1] = *(unsigned int *)RTA_DATA(attr);
|
|
|
+
|
|
|
+ fi->fib_metrics[type-1] = nla_get_u32(attr);
|
|
|
}
|
|
|
- attr = RTA_NEXT(attr, attrlen);
|
|
|
}
|
|
|
}
|
|
|
- if (rta->rta_prefsrc)
|
|
|
- memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
|
|
|
|
|
|
- if (rta->rta_mp) {
|
|
|
- if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
|
|
|
+ if (attrs[RTA_PREFSRC])
|
|
|
+ fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
|
|
|
+
|
|
|
+ if (attrs[RTA_MULTIPATH]) {
|
|
|
+ if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
|
|
|
goto failure;
|
|
|
- if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
|
|
|
+
|
|
|
+ if (attrs[RTA_OIF] &&
|
|
|
+ fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
|
|
|
goto err_inval;
|
|
|
- if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
|
|
|
+
|
|
|
+ if (attrs[RTA_GATEWAY] &&
|
|
|
+ fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
|
|
|
goto err_inval;
|
|
|
} else {
|
|
|
struct dn_fib_nh *nh = fi->fib_nh;
|
|
|
- if (rta->rta_oif)
|
|
|
- nh->nh_oif = *rta->rta_oif;
|
|
|
- if (rta->rta_gw)
|
|
|
- memcpy(&nh->nh_gw, rta->rta_gw, 2);
|
|
|
+
|
|
|
+ if (attrs[RTA_OIF])
|
|
|
+ nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
|
|
|
+
|
|
|
+ if (attrs[RTA_GATEWAY])
|
|
|
+ nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
|
|
|
+
|
|
|
nh->nh_flags = r->rtm_flags;
|
|
|
nh->nh_weight = 1;
|
|
|
}
|
|
|
|
|
|
if (r->rtm_type == RTN_NAT) {
|
|
|
- if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
|
|
|
+ if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
|
|
|
goto err_inval;
|
|
|
- memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2);
|
|
|
+
|
|
|
+ fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
|
|
|
goto link_it;
|
|
|
}
|
|
|
|
|
|
if (dn_fib_props[r->rtm_type].error) {
|
|
|
- if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
|
|
|
+ if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
|
|
|
goto err_inval;
|
|
|
+
|
|
|
goto link_it;
|
|
|
}
|
|
|
|
|
@@ -367,8 +370,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
|
|
|
}
|
|
|
|
|
|
if (fi->fib_prefsrc) {
|
|
|
- if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
|
|
|
- memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
|
|
|
+ if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
|
|
|
+ fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
|
|
|
if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
|
|
|
goto err_inval;
|
|
|
}
|
|
@@ -486,29 +489,24 @@ void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
|
|
|
spin_unlock_bh(&dn_fib_multipath_lock);
|
|
|
}
|
|
|
|
|
|
+const struct nla_policy rtm_dn_policy[RTA_MAX + 1] = {
|
|
|
+ [RTA_DST] = { .type = NLA_U16 },
|
|
|
+ [RTA_SRC] = { .type = NLA_U16 },
|
|
|
+ [RTA_IIF] = { .type = NLA_U32 },
|
|
|
+ [RTA_OIF] = { .type = NLA_U32 },
|
|
|
+ [RTA_GATEWAY] = { .type = NLA_U16 },
|
|
|
+ [RTA_PRIORITY] = { .type = NLA_U32 },
|
|
|
+ [RTA_PREFSRC] = { .type = NLA_U16 },
|
|
|
+ [RTA_METRICS] = { .type = NLA_NESTED },
|
|
|
+ [RTA_MULTIPATH] = { .type = NLA_NESTED },
|
|
|
+ [RTA_TABLE] = { .type = NLA_U32 },
|
|
|
+ [RTA_MARK] = { .type = NLA_U32 },
|
|
|
+};
|
|
|
|
|
|
-static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for(i = 1; i <= RTA_MAX; i++) {
|
|
|
- struct rtattr *attr = rta[i-1];
|
|
|
- if (attr) {
|
|
|
- if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
|
|
|
- return -EINVAL;
|
|
|
- if (i != RTA_MULTIPATH && i != RTA_METRICS &&
|
|
|
- i != RTA_TABLE)
|
|
|
- rta[i-1] = (struct rtattr *)RTA_DATA(attr);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
|
|
|
+static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
|
|
|
{
|
|
|
- if (rta[RTA_TABLE - 1])
|
|
|
- table = nla_get_u32((struct nlattr *) rta[RTA_TABLE - 1]);
|
|
|
+ if (attrs[RTA_TABLE])
|
|
|
+ table = nla_get_u32(attrs[RTA_TABLE]);
|
|
|
|
|
|
return table;
|
|
|
}
|
|
@@ -517,8 +515,9 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
|
|
|
{
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
struct dn_fib_table *tb;
|
|
|
- struct rtattr **rta = arg;
|
|
|
- struct rtmsg *r = NLMSG_DATA(nlh);
|
|
|
+ struct rtmsg *r = nlmsg_data(nlh);
|
|
|
+ struct nlattr *attrs[RTA_MAX+1];
|
|
|
+ int err;
|
|
|
|
|
|
if (!capable(CAP_NET_ADMIN))
|
|
|
return -EPERM;
|
|
@@ -526,22 +525,24 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
|
|
|
if (!net_eq(net, &init_net))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (dn_fib_check_attr(r, rta))
|
|
|
- return -EINVAL;
|
|
|
+ err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
|
|
|
- tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);
|
|
|
- if (tb)
|
|
|
- return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
|
|
|
+ tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
|
|
|
+ if (!tb)
|
|
|
+ return -ESRCH;
|
|
|
|
|
|
- return -ESRCH;
|
|
|
+ return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
|
|
|
}
|
|
|
|
|
|
static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
|
|
{
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
struct dn_fib_table *tb;
|
|
|
- struct rtattr **rta = arg;
|
|
|
- struct rtmsg *r = NLMSG_DATA(nlh);
|
|
|
+ struct rtmsg *r = nlmsg_data(nlh);
|
|
|
+ struct nlattr *attrs[RTA_MAX+1];
|
|
|
+ int err;
|
|
|
|
|
|
if (!capable(CAP_NET_ADMIN))
|
|
|
return -EPERM;
|
|
@@ -549,14 +550,15 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
|
|
|
if (!net_eq(net, &init_net))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (dn_fib_check_attr(r, rta))
|
|
|
- return -EINVAL;
|
|
|
+ err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
|
|
|
- tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);
|
|
|
- if (tb)
|
|
|
- return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
|
|
|
+ tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
|
|
|
+ if (!tb)
|
|
|
+ return -ENOBUFS;
|
|
|
|
|
|
- return -ENOBUFS;
|
|
|
+ return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
|
|
|
}
|
|
|
|
|
|
static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
|
|
@@ -566,10 +568,31 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
|
|
|
struct nlmsghdr nlh;
|
|
|
struct rtmsg rtm;
|
|
|
} req;
|
|
|
- struct dn_kern_rta rta;
|
|
|
+ struct {
|
|
|
+ struct nlattr hdr;
|
|
|
+ __le16 dst;
|
|
|
+ } dst_attr = {
|
|
|
+ .dst = dst,
|
|
|
+ };
|
|
|
+ struct {
|
|
|
+ struct nlattr hdr;
|
|
|
+ __le16 prefsrc;
|
|
|
+ } prefsrc_attr = {
|
|
|
+ .prefsrc = ifa->ifa_local,
|
|
|
+ };
|
|
|
+ struct {
|
|
|
+ struct nlattr hdr;
|
|
|
+ u32 oif;
|
|
|
+ } oif_attr = {
|
|
|
+ .oif = ifa->ifa_dev->dev->ifindex,
|
|
|
+ };
|
|
|
+ struct nlattr *attrs[RTA_MAX+1] = {
|
|
|
+ [RTA_DST] = (struct nlattr *) &dst_attr,
|
|
|
+ [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
|
|
|
+ [RTA_OIF] = (struct nlattr *) &oif_attr,
|
|
|
+ };
|
|
|
|
|
|
memset(&req.rtm, 0, sizeof(req.rtm));
|
|
|
- memset(&rta, 0, sizeof(rta));
|
|
|
|
|
|
if (type == RTN_UNICAST)
|
|
|
tb = dn_fib_get_table(RT_MIN_TABLE, 1);
|
|
@@ -591,14 +614,10 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
|
|
|
req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
|
|
|
req.rtm.rtm_type = type;
|
|
|
|
|
|
- rta.rta_dst = &dst;
|
|
|
- rta.rta_prefsrc = &ifa->ifa_local;
|
|
|
- rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
|
|
|
-
|
|
|
if (cmd == RTM_NEWROUTE)
|
|
|
- tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL);
|
|
|
+ tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
|
|
|
else
|
|
|
- tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);
|
|
|
+ tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
|
|
|
}
|
|
|
|
|
|
static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
|