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

Commit 03c0566

Browse files
ebiedermdavem330
authored andcommitted
mpls: Netlink commands to add, remove, and dump routes
This change adds two new netlink routing attributes: RTA_VIA and RTA_NEWDST. RTA_VIA specifies the specifies the next machine to send a packet to like RTA_GATEWAY. RTA_VIA differs from RTA_GATEWAY in that it includes the address family of the address of the next machine to send a packet to. Currently the MPLS code supports addresses in AF_INET, AF_INET6 and AF_PACKET. For AF_INET and AF_INET6 the destination mac address is acquired from the neighbour table. For AF_PACKET the destination mac_address is specified in the netlink configuration. I think raw destination mac address support with the family AF_PACKET will prove useful. There is MPLS-TP which is defined to operate on machines that do not support internet packets of any flavor. Further seem to be corner cases where it can be useful. At this point I don't care much either way. RTA_NEWDST specifies the destination address to forward the packet with. MPLS typically changes it's destination address at every hop. For a swap operation RTA_NEWDST is specified with a length of one label. For a push operation RTA_NEWDST is specified with two or more labels. For a pop operation RTA_NEWDST is not specified or equivalently an emtpy RTAN_NEWDST is specified. Those new netlink attributes are used to implement handling of rt-netlink RTM_NEWROUTE, RTM_DELROUTE, and RTM_GETROUTE messages, to maintain the MPLS label table. rtm_to_route_config parses a netlink RTM_NEWROUTE or RTM_DELROUTE message, verify no unhandled attributes or unhandled values are present and sets up the data structures for mpls_route_add and mpls_route_del. I did my best to match up with the existing conventions with the caveats that MPLS addresses are all destination-specific-addresses, and so don't properly have a scope. Signed-off-by: "Eric W. Biederman" <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 966bae3 commit 03c0566

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed

include/uapi/linux/rtnetlink.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ enum rtattr_type_t {
303303
RTA_TABLE,
304304
RTA_MARK,
305305
RTA_MFC_STATS,
306+
RTA_VIA,
307+
RTA_NEWDST,
306308
__RTA_MAX
307309
};
308310

@@ -344,6 +346,12 @@ struct rtnexthop {
344346
#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
345347
#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
346348

349+
/* RTA_VIA */
350+
struct rtvia {
351+
__kernel_sa_family_t rtvia_family;
352+
__u8 rtvia_addr[0];
353+
};
354+
347355
/* RTM_CACHEINFO */
348356

349357
struct rta_cacheinfo {

net/mpls/af_mpls.c

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ static struct packet_type mpls_packet_type __read_mostly = {
212212
.func = mpls_forward,
213213
};
214214

215+
const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = {
216+
[RTA_DST] = { .type = NLA_U32 },
217+
[RTA_OIF] = { .type = NLA_U32 },
218+
};
219+
215220
struct mpls_route_config {
216221
u32 rc_protocol;
217222
u32 rc_ifindex;
@@ -410,6 +415,22 @@ static struct notifier_block mpls_dev_notifier = {
410415
.notifier_call = mpls_dev_notify,
411416
};
412417

418+
static int nla_put_via(struct sk_buff *skb,
419+
u16 family, const void *addr, int alen)
420+
{
421+
struct nlattr *nla;
422+
struct rtvia *via;
423+
424+
nla = nla_reserve(skb, RTA_VIA, alen + 2);
425+
if (!nla)
426+
return -EMSGSIZE;
427+
428+
via = nla_data(nla);
429+
via->rtvia_family = family;
430+
memcpy(via->rtvia_addr, addr, alen);
431+
return 0;
432+
}
433+
413434
int nla_put_labels(struct sk_buff *skb, int attrtype,
414435
u8 labels, const u32 label[])
415436
{
@@ -467,6 +488,210 @@ int nla_get_labels(const struct nlattr *nla,
467488
return 0;
468489
}
469490

491+
static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
492+
struct mpls_route_config *cfg)
493+
{
494+
struct rtmsg *rtm;
495+
struct nlattr *tb[RTA_MAX+1];
496+
int index;
497+
int err;
498+
499+
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy);
500+
if (err < 0)
501+
goto errout;
502+
503+
err = -EINVAL;
504+
rtm = nlmsg_data(nlh);
505+
memset(cfg, 0, sizeof(*cfg));
506+
507+
if (rtm->rtm_family != AF_MPLS)
508+
goto errout;
509+
if (rtm->rtm_dst_len != 20)
510+
goto errout;
511+
if (rtm->rtm_src_len != 0)
512+
goto errout;
513+
if (rtm->rtm_tos != 0)
514+
goto errout;
515+
if (rtm->rtm_table != RT_TABLE_MAIN)
516+
goto errout;
517+
/* Any value is acceptable for rtm_protocol */
518+
519+
/* As mpls uses destination specific addresses
520+
* (or source specific address in the case of multicast)
521+
* all addresses have universal scope.
522+
*/
523+
if (rtm->rtm_scope != RT_SCOPE_UNIVERSE)
524+
goto errout;
525+
if (rtm->rtm_type != RTN_UNICAST)
526+
goto errout;
527+
if (rtm->rtm_flags != 0)
528+
goto errout;
529+
530+
cfg->rc_label = LABEL_NOT_SPECIFIED;
531+
cfg->rc_protocol = rtm->rtm_protocol;
532+
cfg->rc_nlflags = nlh->nlmsg_flags;
533+
cfg->rc_nlinfo.portid = NETLINK_CB(skb).portid;
534+
cfg->rc_nlinfo.nlh = nlh;
535+
cfg->rc_nlinfo.nl_net = sock_net(skb->sk);
536+
537+
for (index = 0; index <= RTA_MAX; index++) {
538+
struct nlattr *nla = tb[index];
539+
if (!nla)
540+
continue;
541+
542+
switch(index) {
543+
case RTA_OIF:
544+
cfg->rc_ifindex = nla_get_u32(nla);
545+
break;
546+
case RTA_NEWDST:
547+
if (nla_get_labels(nla, MAX_NEW_LABELS,
548+
&cfg->rc_output_labels,
549+
cfg->rc_output_label))
550+
goto errout;
551+
break;
552+
case RTA_DST:
553+
{
554+
u32 label_count;
555+
if (nla_get_labels(nla, 1, &label_count,
556+
&cfg->rc_label))
557+
goto errout;
558+
559+
/* The first 16 labels are reserved, and may not be set */
560+
if (cfg->rc_label < 16)
561+
goto errout;
562+
563+
break;
564+
}
565+
case RTA_VIA:
566+
{
567+
struct rtvia *via = nla_data(nla);
568+
cfg->rc_via_family = via->rtvia_family;
569+
cfg->rc_via_alen = nla_len(nla) - 2;
570+
if (cfg->rc_via_alen > MAX_VIA_ALEN)
571+
goto errout;
572+
573+
/* Validate the address family */
574+
switch(cfg->rc_via_family) {
575+
case AF_PACKET:
576+
break;
577+
case AF_INET:
578+
if (cfg->rc_via_alen != 4)
579+
goto errout;
580+
break;
581+
case AF_INET6:
582+
if (cfg->rc_via_alen != 16)
583+
goto errout;
584+
break;
585+
default:
586+
/* Unsupported address family */
587+
goto errout;
588+
}
589+
590+
memcpy(cfg->rc_via, via->rtvia_addr, cfg->rc_via_alen);
591+
break;
592+
}
593+
default:
594+
/* Unsupported attribute */
595+
goto errout;
596+
}
597+
}
598+
599+
err = 0;
600+
errout:
601+
return err;
602+
}
603+
604+
static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
605+
{
606+
struct mpls_route_config cfg;
607+
int err;
608+
609+
err = rtm_to_route_config(skb, nlh, &cfg);
610+
if (err < 0)
611+
return err;
612+
613+
return mpls_route_del(&cfg);
614+
}
615+
616+
617+
static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
618+
{
619+
struct mpls_route_config cfg;
620+
int err;
621+
622+
err = rtm_to_route_config(skb, nlh, &cfg);
623+
if (err < 0)
624+
return err;
625+
626+
return mpls_route_add(&cfg);
627+
}
628+
629+
static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
630+
u32 label, struct mpls_route *rt, int flags)
631+
{
632+
struct nlmsghdr *nlh;
633+
struct rtmsg *rtm;
634+
635+
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags);
636+
if (nlh == NULL)
637+
return -EMSGSIZE;
638+
639+
rtm = nlmsg_data(nlh);
640+
rtm->rtm_family = AF_MPLS;
641+
rtm->rtm_dst_len = 20;
642+
rtm->rtm_src_len = 0;
643+
rtm->rtm_tos = 0;
644+
rtm->rtm_table = RT_TABLE_MAIN;
645+
rtm->rtm_protocol = rt->rt_protocol;
646+
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
647+
rtm->rtm_type = RTN_UNICAST;
648+
rtm->rtm_flags = 0;
649+
650+
if (rt->rt_labels &&
651+
nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label))
652+
goto nla_put_failure;
653+
if (nla_put_via(skb, rt->rt_via_family, rt->rt_via, rt->rt_via_alen))
654+
goto nla_put_failure;
655+
if (rt->rt_dev && nla_put_u32(skb, RTA_OIF, rt->rt_dev->ifindex))
656+
goto nla_put_failure;
657+
if (nla_put_labels(skb, RTA_DST, 1, &label))
658+
goto nla_put_failure;
659+
660+
nlmsg_end(skb, nlh);
661+
return 0;
662+
663+
nla_put_failure:
664+
nlmsg_cancel(skb, nlh);
665+
return -EMSGSIZE;
666+
}
667+
668+
static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
669+
{
670+
struct net *net = sock_net(skb->sk);
671+
unsigned int index;
672+
673+
ASSERT_RTNL();
674+
675+
index = cb->args[0];
676+
if (index < 16)
677+
index = 16;
678+
679+
for (; index < net->mpls.platform_labels; index++) {
680+
struct mpls_route *rt;
681+
rt = net->mpls.platform_label[index];
682+
if (!rt)
683+
continue;
684+
685+
if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid,
686+
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
687+
index, rt, NLM_F_MULTI) < 0)
688+
break;
689+
}
690+
cb->args[0] = index;
691+
692+
return skb->len;
693+
}
694+
470695
static int resize_platform_label_table(struct net *net, size_t limit)
471696
{
472697
size_t size = sizeof(struct mpls_route *) * limit;
@@ -662,6 +887,9 @@ static int __init mpls_init(void)
662887

663888
dev_add_pack(&mpls_packet_type);
664889

890+
rtnl_register(PF_MPLS, RTM_NEWROUTE, mpls_rtm_newroute, NULL, NULL);
891+
rtnl_register(PF_MPLS, RTM_DELROUTE, mpls_rtm_delroute, NULL, NULL);
892+
rtnl_register(PF_MPLS, RTM_GETROUTE, NULL, mpls_dump_routes, NULL);
665893
err = 0;
666894
out:
667895
return err;
@@ -674,6 +902,7 @@ module_init(mpls_init);
674902

675903
static void __exit mpls_exit(void)
676904
{
905+
rtnl_unregister_all(PF_MPLS);
677906
dev_remove_pack(&mpls_packet_type);
678907
unregister_netdevice_notifier(&mpls_dev_notifier);
679908
unregister_pernet_subsys(&mpls_net_ops);

0 commit comments

Comments
 (0)