20
20
21
21
#include <net/mctp.h>
22
22
#include <net/mctpdevice.h>
23
+ #include <net/netlink.h>
24
+ #include <net/sock.h>
23
25
24
26
/* route output callbacks */
25
27
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)
36
38
return 0 ;
37
39
}
38
40
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 )
41
42
{
42
43
unsigned int mtu ;
43
44
int rc ;
@@ -182,20 +183,29 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt,
182
183
}
183
184
184
185
/* 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 )
186
189
{
187
190
struct net * net = dev_net (mdev -> dev );
188
191
struct mctp_route * rt , * ert ;
189
192
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
+
190
199
rt = mctp_route_alloc ();
191
200
if (!rt )
192
201
return - ENOMEM ;
193
202
194
- rt -> min = addr ;
195
- rt -> max = addr ;
203
+ rt -> min = daddr_start ;
204
+ rt -> max = daddr_start + daddr_extent ;
205
+ rt -> mtu = mtu ;
196
206
rt -> dev = mdev ;
197
207
dev_hold (rt -> dev -> dev );
198
- rt -> output = mctp_route_input ;
208
+ rt -> output = is_local ? mctp_route_input : mctp_route_output ;
199
209
200
210
ASSERT_RTNL ();
201
211
/* Prevent duplicate identical routes. */
@@ -211,22 +221,43 @@ int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr)
211
221
return 0 ;
212
222
}
213
223
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 )
215
226
{
216
227
struct net * net = dev_net (mdev -> dev );
217
228
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;
218
237
219
238
ASSERT_RTNL ();
220
239
221
240
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 ) {
223
243
list_del_rcu (& rt -> list );
224
244
/* TODO: immediate RTM_DELROUTE */
225
245
mctp_route_release (rt );
246
+ dropped = true;
226
247
}
227
248
}
228
249
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 );
230
261
}
231
262
232
263
/* removes all entries for a given device */
@@ -294,6 +325,204 @@ static struct packet_type mctp_packet_type = {
294
325
.func = mctp_pkttype_receive ,
295
326
};
296
327
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
+
297
526
/* net namespace implementation */
298
527
static int __net_init mctp_routes_net_init (struct net * net )
299
528
{
@@ -319,11 +548,22 @@ static struct pernet_operations mctp_net_ops = {
319
548
int __init mctp_routes_init (void )
320
549
{
321
550
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
+
322
559
return register_pernet_subsys (& mctp_net_ops );
323
560
}
324
561
325
562
void __exit mctp_routes_exit (void )
326
563
{
327
564
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 );
328
568
dev_remove_pack (& mctp_packet_type );
329
569
}
0 commit comments