Skip to content

Commit c89359a

Browse files
roopa-prabhudavem330
authored andcommitted
mpls: support for dead routes
Adds support for RTNH_F_DEAD and RTNH_F_LINKDOWN flags on mpls routes due to link events. Also adds code to ignore dead routes during route selection. Unlike ip routes, mpls routes are not deleted when the route goes dead. This is current mpls behaviour and this patch does not change that. With this patch however, routes will be marked dead. dead routes are not notified to userspace (this is consistent with ipv4 routes). dead routes: ----------- $ip -f mpls route show 100 nexthop as to 200 via inet 10.1.1.2 dev swp1 nexthop as to 700 via inet 10.1.1.6 dev swp2 $ip link set dev swp1 down $ip link show dev swp1 4: swp1: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 00:02:00:00:00:01 brd ff:ff:ff:ff:ff:ff $ip -f mpls route show 100 nexthop as to 200 via inet 10.1.1.2 dev swp1 dead linkdown nexthop as to 700 via inet 10.1.1.6 dev swp2 linkdown routes: ---------------- $ip -f mpls route show 100 nexthop as to 200 via inet 10.1.1.2 dev swp1 nexthop as to 700 via inet 10.1.1.6 dev swp2 $ip link show dev swp1 4: swp1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 00:02:00:00:00:01 brd ff:ff:ff:ff:ff:ff /* carrier goes down */ $ip link show dev swp1 4: swp1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 00:02:00:00:00:01 brd ff:ff:ff:ff:ff:ff $ip -f mpls route show 100 nexthop as to 200 via inet 10.1.1.2 dev swp1 linkdown nexthop as to 700 via inet 10.1.1.6 dev swp2 Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Acked-by: Robert Shearman <rshearma@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 9f4842a commit c89359a

File tree

2 files changed

+159
-28
lines changed

2 files changed

+159
-28
lines changed

net/mpls/af_mpls.c

Lines changed: 157 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,15 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
9696
}
9797
EXPORT_SYMBOL_GPL(mpls_pkt_too_big);
9898

99-
static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
100-
struct sk_buff *skb, bool bos)
99+
static u32 mpls_multipath_hash(struct mpls_route *rt,
100+
struct sk_buff *skb, bool bos)
101101
{
102102
struct mpls_entry_decoded dec;
103103
struct mpls_shim_hdr *hdr;
104104
bool eli_seen = false;
105105
int label_index;
106-
int nh_index = 0;
107106
u32 hash = 0;
108107

109-
/* No need to look further into packet if there's only
110-
* one path
111-
*/
112-
if (rt->rt_nhn == 1)
113-
goto out;
114-
115108
for (label_index = 0; label_index < MAX_MP_SELECT_LABELS && !bos;
116109
label_index++) {
117110
if (!pskb_may_pull(skb, sizeof(*hdr) * label_index))
@@ -165,7 +158,38 @@ static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
165158
}
166159
}
167160

168-
nh_index = hash % rt->rt_nhn;
161+
return hash;
162+
}
163+
164+
static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
165+
struct sk_buff *skb, bool bos)
166+
{
167+
int alive = ACCESS_ONCE(rt->rt_nhn_alive);
168+
u32 hash = 0;
169+
int nh_index = 0;
170+
int n = 0;
171+
172+
/* No need to look further into packet if there's only
173+
* one path
174+
*/
175+
if (rt->rt_nhn == 1)
176+
goto out;
177+
178+
if (alive <= 0)
179+
return NULL;
180+
181+
hash = mpls_multipath_hash(rt, skb, bos);
182+
nh_index = hash % alive;
183+
if (alive == rt->rt_nhn)
184+
goto out;
185+
for_nexthops(rt) {
186+
if (nh->nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
187+
continue;
188+
if (n == nh_index)
189+
return nh;
190+
n++;
191+
} endfor_nexthops(rt);
192+
169193
out:
170194
return &rt->rt_nh[nh_index];
171195
}
@@ -365,6 +389,7 @@ static struct mpls_route *mpls_rt_alloc(int num_nh, u8 max_alen)
365389
GFP_KERNEL);
366390
if (rt) {
367391
rt->rt_nhn = num_nh;
392+
rt->rt_nhn_alive = num_nh;
368393
rt->rt_max_alen = max_alen_aligned;
369394
}
370395

@@ -536,6 +561,16 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
536561

537562
RCU_INIT_POINTER(nh->nh_dev, dev);
538563

564+
if (!(dev->flags & IFF_UP)) {
565+
nh->nh_flags |= RTNH_F_DEAD;
566+
} else {
567+
unsigned int flags;
568+
569+
flags = dev_get_flags(dev);
570+
if (!(flags & (IFF_RUNNING | IFF_LOWER_UP)))
571+
nh->nh_flags |= RTNH_F_LINKDOWN;
572+
}
573+
539574
return 0;
540575

541576
errout:
@@ -570,15 +605,18 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
570605
if (err)
571606
goto errout;
572607

608+
if (nh->nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
609+
rt->rt_nhn_alive--;
610+
573611
return 0;
574612

575613
errout:
576614
return err;
577615
}
578616

579617
static int mpls_nh_build(struct net *net, struct mpls_route *rt,
580-
struct mpls_nh *nh, int oif,
581-
struct nlattr *via, struct nlattr *newdst)
618+
struct mpls_nh *nh, int oif, struct nlattr *via,
619+
struct nlattr *newdst)
582620
{
583621
int err = -ENOMEM;
584622

@@ -681,11 +719,13 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
681719
goto errout;
682720

683721
err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
684-
rtnh->rtnh_ifindex, nla_via,
685-
nla_newdst);
722+
rtnh->rtnh_ifindex, nla_via, nla_newdst);
686723
if (err)
687724
goto errout;
688725

726+
if (nh->nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
727+
rt->rt_nhn_alive--;
728+
689729
rtnh = rtnh_next(rtnh, &remaining);
690730
nhs++;
691731
} endfor_nexthops(rt);
@@ -875,55 +915,124 @@ static struct mpls_dev *mpls_add_dev(struct net_device *dev)
875915
return ERR_PTR(err);
876916
}
877917

878-
static void mpls_ifdown(struct net_device *dev)
918+
static void mpls_ifdown(struct net_device *dev, int event)
879919
{
880920
struct mpls_route __rcu **platform_label;
881921
struct net *net = dev_net(dev);
882-
struct mpls_dev *mdev;
883922
unsigned index;
884923

885924
platform_label = rtnl_dereference(net->mpls.platform_label);
886925
for (index = 0; index < net->mpls.platform_labels; index++) {
887926
struct mpls_route *rt = rtnl_dereference(platform_label[index]);
927+
888928
if (!rt)
889929
continue;
890-
for_nexthops(rt) {
930+
931+
change_nexthops(rt) {
891932
if (rtnl_dereference(nh->nh_dev) != dev)
892933
continue;
893-
nh->nh_dev = NULL;
934+
switch (event) {
935+
case NETDEV_DOWN:
936+
case NETDEV_UNREGISTER:
937+
nh->nh_flags |= RTNH_F_DEAD;
938+
/* fall through */
939+
case NETDEV_CHANGE:
940+
nh->nh_flags |= RTNH_F_LINKDOWN;
941+
ACCESS_ONCE(rt->rt_nhn_alive) = rt->rt_nhn_alive - 1;
942+
break;
943+
}
944+
if (event == NETDEV_UNREGISTER)
945+
RCU_INIT_POINTER(nh->nh_dev, NULL);
894946
} endfor_nexthops(rt);
895947
}
896948

897-
mdev = mpls_dev_get(dev);
898-
if (!mdev)
899-
return;
900949

901-
mpls_dev_sysctl_unregister(mdev);
950+
return;
951+
}
952+
953+
static void mpls_ifup(struct net_device *dev, unsigned int nh_flags)
954+
{
955+
struct mpls_route __rcu **platform_label;
956+
struct net *net = dev_net(dev);
957+
unsigned index;
958+
int alive;
959+
960+
platform_label = rtnl_dereference(net->mpls.platform_label);
961+
for (index = 0; index < net->mpls.platform_labels; index++) {
962+
struct mpls_route *rt = rtnl_dereference(platform_label[index]);
963+
964+
if (!rt)
965+
continue;
966+
967+
alive = 0;
968+
change_nexthops(rt) {
969+
struct net_device *nh_dev =
970+
rtnl_dereference(nh->nh_dev);
971+
972+
if (!(nh->nh_flags & nh_flags)) {
973+
alive++;
974+
continue;
975+
}
976+
if (nh_dev != dev)
977+
continue;
978+
alive++;
979+
nh->nh_flags &= ~nh_flags;
980+
} endfor_nexthops(rt);
902981

903-
RCU_INIT_POINTER(dev->mpls_ptr, NULL);
982+
ACCESS_ONCE(rt->rt_nhn_alive) = alive;
983+
}
904984

905-
kfree_rcu(mdev, rcu);
985+
return;
906986
}
907987

908988
static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
909989
void *ptr)
910990
{
911991
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
912992
struct mpls_dev *mdev;
993+
unsigned int flags;
913994

914-
switch(event) {
915-
case NETDEV_REGISTER:
995+
if (event == NETDEV_REGISTER) {
916996
/* For now just support ethernet devices */
917997
if ((dev->type == ARPHRD_ETHER) ||
918998
(dev->type == ARPHRD_LOOPBACK)) {
919999
mdev = mpls_add_dev(dev);
9201000
if (IS_ERR(mdev))
9211001
return notifier_from_errno(PTR_ERR(mdev));
9221002
}
923-
break;
1003+
return NOTIFY_OK;
1004+
}
9241005

1006+
mdev = mpls_dev_get(dev);
1007+
if (!mdev)
1008+
return NOTIFY_OK;
1009+
1010+
switch (event) {
1011+
case NETDEV_DOWN:
1012+
mpls_ifdown(dev, event);
1013+
break;
1014+
case NETDEV_UP:
1015+
flags = dev_get_flags(dev);
1016+
if (flags & (IFF_RUNNING | IFF_LOWER_UP))
1017+
mpls_ifup(dev, RTNH_F_DEAD | RTNH_F_LINKDOWN);
1018+
else
1019+
mpls_ifup(dev, RTNH_F_DEAD);
1020+
break;
1021+
case NETDEV_CHANGE:
1022+
flags = dev_get_flags(dev);
1023+
if (flags & (IFF_RUNNING | IFF_LOWER_UP))
1024+
mpls_ifup(dev, RTNH_F_DEAD | RTNH_F_LINKDOWN);
1025+
else
1026+
mpls_ifdown(dev, event);
1027+
break;
9251028
case NETDEV_UNREGISTER:
926-
mpls_ifdown(dev);
1029+
mpls_ifdown(dev, event);
1030+
mdev = mpls_dev_get(dev);
1031+
if (mdev) {
1032+
mpls_dev_sysctl_unregister(mdev);
1033+
RCU_INIT_POINTER(dev->mpls_ptr, NULL);
1034+
kfree_rcu(mdev, rcu);
1035+
}
9271036
break;
9281037
case NETDEV_CHANGENAME:
9291038
mdev = mpls_dev_get(dev);
@@ -1237,9 +1346,15 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
12371346
dev = rtnl_dereference(nh->nh_dev);
12381347
if (dev && nla_put_u32(skb, RTA_OIF, dev->ifindex))
12391348
goto nla_put_failure;
1349+
if (nh->nh_flags & RTNH_F_LINKDOWN)
1350+
rtm->rtm_flags |= RTNH_F_LINKDOWN;
1351+
if (nh->nh_flags & RTNH_F_DEAD)
1352+
rtm->rtm_flags |= RTNH_F_DEAD;
12401353
} else {
12411354
struct rtnexthop *rtnh;
12421355
struct nlattr *mp;
1356+
int dead = 0;
1357+
int linkdown = 0;
12431358

12441359
mp = nla_nest_start(skb, RTA_MULTIPATH);
12451360
if (!mp)
@@ -1253,6 +1368,15 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
12531368
dev = rtnl_dereference(nh->nh_dev);
12541369
if (dev)
12551370
rtnh->rtnh_ifindex = dev->ifindex;
1371+
if (nh->nh_flags & RTNH_F_LINKDOWN) {
1372+
rtnh->rtnh_flags |= RTNH_F_LINKDOWN;
1373+
linkdown++;
1374+
}
1375+
if (nh->nh_flags & RTNH_F_DEAD) {
1376+
rtnh->rtnh_flags |= RTNH_F_DEAD;
1377+
dead++;
1378+
}
1379+
12561380
if (nh->nh_labels && nla_put_labels(skb, RTA_NEWDST,
12571381
nh->nh_labels,
12581382
nh->nh_label))
@@ -1266,6 +1390,11 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
12661390
rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
12671391
} endfor_nexthops(rt);
12681392

1393+
if (linkdown == rt->rt_nhn)
1394+
rtm->rtm_flags |= RTNH_F_LINKDOWN;
1395+
if (dead == rt->rt_nhn)
1396+
rtm->rtm_flags |= RTNH_F_DEAD;
1397+
12691398
nla_nest_end(skb, mp);
12701399
}
12711400

net/mpls/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ enum mpls_payload_type {
4141

4242
struct mpls_nh { /* next hop label forwarding entry */
4343
struct net_device __rcu *nh_dev;
44+
unsigned int nh_flags;
4445
u32 nh_label[MAX_NEW_LABELS];
4546
u8 nh_labels;
4647
u8 nh_via_alen;
@@ -74,6 +75,7 @@ struct mpls_route { /* next hop label forwarding entry */
7475
u8 rt_payload_type;
7576
u8 rt_max_alen;
7677
unsigned int rt_nhn;
78+
unsigned int rt_nhn_alive;
7779
struct mpls_nh rt_nh[0];
7880
};
7981

0 commit comments

Comments
 (0)