Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 06d2f4c

Browse files
mkjdavem330
authored andcommitted
mctp: Add netlink route management
This change adds RTM_GETROUTE, RTM_NEWROUTE & RTM_DELROUTE handlers, allowing management of the MCTP route table. Includes changes from Jeremy Kerr <[email protected]>. Signed-off-by: Matt Johnston <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 889b7da commit 06d2f4c

File tree

2 files changed

+251
-9
lines changed

2 files changed

+251
-9
lines changed

include/net/mctp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
111111
struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
112112

113113
/* routing <--> device interface */
114+
unsigned int mctp_default_net(struct net *net);
115+
int mctp_default_net_set(struct net *net, unsigned int index);
114116
int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr);
115117
int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr);
116118
void mctp_route_remove_dev(struct mctp_dev *mdev);

net/mctp/route.c

Lines changed: 249 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include <net/mctp.h>
2222
#include <net/mctpdevice.h>
23+
#include <net/netlink.h>
24+
#include <net/sock.h>
2325

2426
/* route output callbacks */
2527
static int mctp_route_discard(struct mctp_route *route, struct sk_buff *skb)
@@ -36,8 +38,7 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
3638
return 0;
3739
}
3840

39-
static int __always_unused mctp_route_output(struct mctp_route *route,
40-
struct sk_buff *skb)
41+
static int mctp_route_output(struct mctp_route *route, struct sk_buff *skb)
4142
{
4243
unsigned int mtu;
4344
int rc;
@@ -182,20 +183,29 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
182183
}
183184

184185
/* route management */
185-
int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr)
186+
static int mctp_route_add(struct mctp_dev *mdev, mctp_eid_t daddr_start,
187+
unsigned int daddr_extent, unsigned int mtu,
188+
bool is_local)
186189
{
187190
struct net *net = dev_net(mdev->dev);
188191
struct mctp_route *rt, *ert;
189192

193+
if (!mctp_address_ok(daddr_start))
194+
return -EINVAL;
195+
196+
if (daddr_extent > 0xff || daddr_start + daddr_extent >= 255)
197+
return -EINVAL;
198+
190199
rt = mctp_route_alloc();
191200
if (!rt)
192201
return -ENOMEM;
193202

194-
rt->min = addr;
195-
rt->max = addr;
203+
rt->min = daddr_start;
204+
rt->max = daddr_start + daddr_extent;
205+
rt->mtu = mtu;
196206
rt->dev = mdev;
197207
dev_hold(rt->dev->dev);
198-
rt->output = mctp_route_input;
208+
rt->output = is_local ? mctp_route_input : mctp_route_output;
199209

200210
ASSERT_RTNL();
201211
/* Prevent duplicate identical routes. */
@@ -211,22 +221,43 @@ int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr)
211221
return 0;
212222
}
213223

214-
int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr)
224+
static int mctp_route_remove(struct mctp_dev *mdev, mctp_eid_t daddr_start,
225+
unsigned int daddr_extent)
215226
{
216227
struct net *net = dev_net(mdev->dev);
217228
struct mctp_route *rt, *tmp;
229+
mctp_eid_t daddr_end;
230+
bool dropped;
231+
232+
if (daddr_extent > 0xff || daddr_start + daddr_extent >= 255)
233+
return -EINVAL;
234+
235+
daddr_end = daddr_start + daddr_extent;
236+
dropped = false;
218237

219238
ASSERT_RTNL();
220239

221240
list_for_each_entry_safe(rt, tmp, &net->mctp.routes, list) {
222-
if (rt->dev == mdev && rt->min == addr && rt->max == addr) {
241+
if (rt->dev == mdev &&
242+
rt->min == daddr_start && rt->max == daddr_end) {
223243
list_del_rcu(&rt->list);
224244
/* TODO: immediate RTM_DELROUTE */
225245
mctp_route_release(rt);
246+
dropped = true;
226247
}
227248
}
228249

229-
return 0;
250+
return dropped ? 0 : -ENOENT;
251+
}
252+
253+
int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr)
254+
{
255+
return mctp_route_add(mdev, addr, 0, 0, true);
256+
}
257+
258+
int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr)
259+
{
260+
return mctp_route_remove(mdev, addr, 0);
230261
}
231262

232263
/* removes all entries for a given device */
@@ -294,6 +325,204 @@ static struct packet_type mctp_packet_type = {
294325
.func = mctp_pkttype_receive,
295326
};
296327

328+
/* netlink interface */
329+
330+
static const struct nla_policy rta_mctp_policy[RTA_MAX + 1] = {
331+
[RTA_DST] = { .type = NLA_U8 },
332+
[RTA_METRICS] = { .type = NLA_NESTED },
333+
[RTA_OIF] = { .type = NLA_U32 },
334+
};
335+
336+
/* Common part for RTM_NEWROUTE and RTM_DELROUTE parsing.
337+
* tb must hold RTA_MAX+1 elements.
338+
*/
339+
static int mctp_route_nlparse(struct sk_buff *skb, struct nlmsghdr *nlh,
340+
struct netlink_ext_ack *extack,
341+
struct nlattr **tb, struct rtmsg **rtm,
342+
struct mctp_dev **mdev, mctp_eid_t *daddr_start)
343+
{
344+
struct net *net = sock_net(skb->sk);
345+
struct net_device *dev;
346+
unsigned int ifindex;
347+
int rc;
348+
349+
rc = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
350+
rta_mctp_policy, extack);
351+
if (rc < 0) {
352+
NL_SET_ERR_MSG(extack, "incorrect format");
353+
return rc;
354+
}
355+
356+
if (!tb[RTA_DST]) {
357+
NL_SET_ERR_MSG(extack, "dst EID missing");
358+
return -EINVAL;
359+
}
360+
*daddr_start = nla_get_u8(tb[RTA_DST]);
361+
362+
if (!tb[RTA_OIF]) {
363+
NL_SET_ERR_MSG(extack, "ifindex missing");
364+
return -EINVAL;
365+
}
366+
ifindex = nla_get_u32(tb[RTA_OIF]);
367+
368+
*rtm = nlmsg_data(nlh);
369+
if ((*rtm)->rtm_family != AF_MCTP) {
370+
NL_SET_ERR_MSG(extack, "route family must be AF_MCTP");
371+
return -EINVAL;
372+
}
373+
374+
dev = __dev_get_by_index(net, ifindex);
375+
if (!dev) {
376+
NL_SET_ERR_MSG(extack, "bad ifindex");
377+
return -ENODEV;
378+
}
379+
*mdev = mctp_dev_get_rtnl(dev);
380+
if (!*mdev)
381+
return -ENODEV;
382+
383+
if (dev->flags & IFF_LOOPBACK) {
384+
NL_SET_ERR_MSG(extack, "no routes to loopback");
385+
return -EINVAL;
386+
}
387+
388+
return 0;
389+
}
390+
391+
static int mctp_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
392+
struct netlink_ext_ack *extack)
393+
{
394+
struct nlattr *tb[RTA_MAX + 1];
395+
mctp_eid_t daddr_start;
396+
struct mctp_dev *mdev;
397+
struct rtmsg *rtm;
398+
unsigned int mtu;
399+
int rc;
400+
401+
rc = mctp_route_nlparse(skb, nlh, extack, tb,
402+
&rtm, &mdev, &daddr_start);
403+
if (rc < 0)
404+
return rc;
405+
406+
if (rtm->rtm_type != RTN_UNICAST) {
407+
NL_SET_ERR_MSG(extack, "rtm_type must be RTN_UNICAST");
408+
return -EINVAL;
409+
}
410+
411+
/* TODO: parse mtu from nlparse */
412+
mtu = 0;
413+
414+
rc = mctp_route_add(mdev, daddr_start, rtm->rtm_dst_len, mtu, false);
415+
return rc;
416+
}
417+
418+
static int mctp_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
419+
struct netlink_ext_ack *extack)
420+
{
421+
struct nlattr *tb[RTA_MAX + 1];
422+
mctp_eid_t daddr_start;
423+
struct mctp_dev *mdev;
424+
struct rtmsg *rtm;
425+
int rc;
426+
427+
rc = mctp_route_nlparse(skb, nlh, extack, tb,
428+
&rtm, &mdev, &daddr_start);
429+
if (rc < 0)
430+
return rc;
431+
432+
/* we only have unicast routes */
433+
if (rtm->rtm_type != RTN_UNICAST)
434+
return -EINVAL;
435+
436+
rc = mctp_route_remove(mdev, daddr_start, rtm->rtm_dst_len);
437+
return rc;
438+
}
439+
440+
static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt,
441+
u32 portid, u32 seq, int event, unsigned int flags)
442+
{
443+
struct nlmsghdr *nlh;
444+
struct rtmsg *hdr;
445+
void *metrics;
446+
447+
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags);
448+
if (!nlh)
449+
return -EMSGSIZE;
450+
451+
hdr = nlmsg_data(nlh);
452+
hdr->rtm_family = AF_MCTP;
453+
454+
/* we use the _len fields as a number of EIDs, rather than
455+
* a number of bits in the address
456+
*/
457+
hdr->rtm_dst_len = rt->max - rt->min;
458+
hdr->rtm_src_len = 0;
459+
hdr->rtm_tos = 0;
460+
hdr->rtm_table = RT_TABLE_DEFAULT;
461+
hdr->rtm_protocol = RTPROT_STATIC; /* everything is user-defined */
462+
hdr->rtm_scope = RT_SCOPE_LINK; /* TODO: scope in mctp_route? */
463+
hdr->rtm_type = RTN_ANYCAST; /* TODO: type from route */
464+
465+
if (nla_put_u8(skb, RTA_DST, rt->min))
466+
goto cancel;
467+
468+
metrics = nla_nest_start_noflag(skb, RTA_METRICS);
469+
if (!metrics)
470+
goto cancel;
471+
472+
if (rt->mtu) {
473+
if (nla_put_u32(skb, RTAX_MTU, rt->mtu))
474+
goto cancel;
475+
}
476+
477+
nla_nest_end(skb, metrics);
478+
479+
if (rt->dev) {
480+
if (nla_put_u32(skb, RTA_OIF, rt->dev->dev->ifindex))
481+
goto cancel;
482+
}
483+
484+
/* TODO: conditional neighbour physaddr? */
485+
486+
nlmsg_end(skb, nlh);
487+
488+
return 0;
489+
490+
cancel:
491+
nlmsg_cancel(skb, nlh);
492+
return -EMSGSIZE;
493+
}
494+
495+
static int mctp_dump_rtinfo(struct sk_buff *skb, struct netlink_callback *cb)
496+
{
497+
struct net *net = sock_net(skb->sk);
498+
struct mctp_route *rt;
499+
int s_idx, idx;
500+
501+
/* TODO: allow filtering on route data, possibly under
502+
* cb->strict_check
503+
*/
504+
505+
/* TODO: change to struct overlay */
506+
s_idx = cb->args[0];
507+
idx = 0;
508+
509+
rcu_read_lock();
510+
list_for_each_entry_rcu(rt, &net->mctp.routes, list) {
511+
if (idx++ < s_idx)
512+
continue;
513+
if (mctp_fill_rtinfo(skb, rt,
514+
NETLINK_CB(cb->skb).portid,
515+
cb->nlh->nlmsg_seq,
516+
RTM_NEWROUTE, NLM_F_MULTI) < 0)
517+
break;
518+
}
519+
520+
rcu_read_unlock();
521+
cb->args[0] = idx;
522+
523+
return skb->len;
524+
}
525+
297526
/* net namespace implementation */
298527
static int __net_init mctp_routes_net_init(struct net *net)
299528
{
@@ -319,11 +548,22 @@ static struct pernet_operations mctp_net_ops = {
319548
int __init mctp_routes_init(void)
320549
{
321550
dev_add_pack(&mctp_packet_type);
551+
552+
rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_GETROUTE,
553+
NULL, mctp_dump_rtinfo, 0);
554+
rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_NEWROUTE,
555+
mctp_newroute, NULL, 0);
556+
rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_DELROUTE,
557+
mctp_delroute, NULL, 0);
558+
322559
return register_pernet_subsys(&mctp_net_ops);
323560
}
324561

325562
void __exit mctp_routes_exit(void)
326563
{
327564
unregister_pernet_subsys(&mctp_net_ops);
565+
rtnl_unregister(PF_MCTP, RTM_DELROUTE);
566+
rtnl_unregister(PF_MCTP, RTM_NEWROUTE);
567+
rtnl_unregister(PF_MCTP, RTM_GETROUTE);
328568
dev_remove_pack(&mctp_packet_type);
329569
}

0 commit comments

Comments
 (0)