Skip to content

Commit 1b69e7e

Browse files
shorman-netronomedavem330
authored andcommitted
ipip: support MPLS over IPv4
Extend the IPIP driver to support MPLS over IPv4. The implementation is an extension of existing support for IPv4 over IPv4 and is based of multiple inner-protocol support for the SIT driver. Signed-off-by: Simon Horman <simon.horman@netronome.com> Reviewed-by: Dinan Gunawardena <dinan.gunawardena@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 49dbe7a commit 1b69e7e

File tree

1 file changed

+121
-16
lines changed

1 file changed

+121
-16
lines changed

net/ipv4/ipip.c

Lines changed: 121 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,14 @@ static int ipip_err(struct sk_buff *skb, u32 info)
148148

149149
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
150150
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
151-
t->parms.link, 0, IPPROTO_IPIP, 0);
151+
t->parms.link, 0, iph->protocol, 0);
152152
err = 0;
153153
goto out;
154154
}
155155

156156
if (type == ICMP_REDIRECT) {
157157
ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
158-
IPPROTO_IPIP, 0);
158+
iph->protocol, 0);
159159
err = 0;
160160
goto out;
161161
}
@@ -177,12 +177,19 @@ static int ipip_err(struct sk_buff *skb, u32 info)
177177
return err;
178178
}
179179

180-
static const struct tnl_ptk_info tpi = {
180+
static const struct tnl_ptk_info ipip_tpi = {
181181
/* no tunnel info required for ipip. */
182182
.proto = htons(ETH_P_IP),
183183
};
184184

185-
static int ipip_rcv(struct sk_buff *skb)
185+
#if IS_ENABLED(CONFIG_MPLS)
186+
static const struct tnl_ptk_info mplsip_tpi = {
187+
/* no tunnel info required for mplsip. */
188+
.proto = htons(ETH_P_MPLS_UC),
189+
};
190+
#endif
191+
192+
static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
186193
{
187194
struct net *net = dev_net(skb->dev);
188195
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
@@ -193,11 +200,23 @@ static int ipip_rcv(struct sk_buff *skb)
193200
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
194201
iph->saddr, iph->daddr, 0);
195202
if (tunnel) {
203+
const struct tnl_ptk_info *tpi;
204+
205+
if (tunnel->parms.iph.protocol != ipproto &&
206+
tunnel->parms.iph.protocol != 0)
207+
goto drop;
208+
196209
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
197210
goto drop;
198-
if (iptunnel_pull_header(skb, 0, tpi.proto, false))
211+
#if IS_ENABLED(CONFIG_MPLS)
212+
if (ipproto == IPPROTO_MPLS)
213+
tpi = &mplsip_tpi;
214+
else
215+
#endif
216+
tpi = &ipip_tpi;
217+
if (iptunnel_pull_header(skb, 0, tpi->proto, false))
199218
goto drop;
200-
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
219+
return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
201220
}
202221

203222
return -1;
@@ -207,24 +226,51 @@ static int ipip_rcv(struct sk_buff *skb)
207226
return 0;
208227
}
209228

229+
static int ipip_rcv(struct sk_buff *skb)
230+
{
231+
return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
232+
}
233+
234+
#if IS_ENABLED(CONFIG_MPLS)
235+
static int mplsip_rcv(struct sk_buff *skb)
236+
{
237+
return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
238+
}
239+
#endif
240+
210241
/*
211242
* This function assumes it is being called from dev_queue_xmit()
212243
* and that skb is filled properly by that function.
213244
*/
214-
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
245+
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
246+
struct net_device *dev)
215247
{
216248
struct ip_tunnel *tunnel = netdev_priv(dev);
217249
const struct iphdr *tiph = &tunnel->parms.iph;
250+
u8 ipproto;
251+
252+
switch (skb->protocol) {
253+
case htons(ETH_P_IP):
254+
ipproto = IPPROTO_IPIP;
255+
break;
256+
#if IS_ENABLED(CONFIG_MPLS)
257+
case htons(ETH_P_MPLS_UC):
258+
ipproto = IPPROTO_MPLS;
259+
break;
260+
#endif
261+
default:
262+
goto tx_error;
263+
}
218264

219-
if (unlikely(skb->protocol != htons(ETH_P_IP)))
265+
if (tiph->protocol != ipproto && tiph->protocol != 0)
220266
goto tx_error;
221267

222268
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
223269
goto tx_error;
224270

225-
skb_set_inner_ipproto(skb, IPPROTO_IPIP);
271+
skb_set_inner_ipproto(skb, ipproto);
226272

227-
ip_tunnel_xmit(skb, dev, tiph, tiph->protocol);
273+
ip_tunnel_xmit(skb, dev, tiph, ipproto);
228274
return NETDEV_TX_OK;
229275

230276
tx_error:
@@ -234,6 +280,20 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
234280
return NETDEV_TX_OK;
235281
}
236282

283+
static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
284+
{
285+
switch (ipproto) {
286+
case 0:
287+
case IPPROTO_IPIP:
288+
#if IS_ENABLED(CONFIG_MPLS)
289+
case IPPROTO_MPLS:
290+
#endif
291+
return true;
292+
}
293+
294+
return false;
295+
}
296+
237297
static int
238298
ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
239299
{
@@ -244,7 +304,8 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
244304
return -EFAULT;
245305

246306
if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
247-
if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
307+
if (p.iph.version != 4 ||
308+
!ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) ||
248309
p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
249310
return -EINVAL;
250311
}
@@ -301,10 +362,23 @@ static int ipip_tunnel_init(struct net_device *dev)
301362

302363
tunnel->tun_hlen = 0;
303364
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
304-
tunnel->parms.iph.protocol = IPPROTO_IPIP;
305365
return ip_tunnel_init(dev);
306366
}
307367

368+
static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
369+
{
370+
u8 proto;
371+
372+
if (!data || !data[IFLA_IPTUN_PROTO])
373+
return 0;
374+
375+
proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
376+
if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
377+
return -EINVAL;
378+
379+
return 0;
380+
}
381+
308382
static void ipip_netlink_parms(struct nlattr *data[],
309383
struct ip_tunnel_parm *parms)
310384
{
@@ -335,6 +409,9 @@ static void ipip_netlink_parms(struct nlattr *data[],
335409
if (data[IFLA_IPTUN_TOS])
336410
parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
337411

412+
if (data[IFLA_IPTUN_PROTO])
413+
parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
414+
338415
if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
339416
parms->iph.frag_off = htons(IP_DF);
340417
}
@@ -427,6 +504,8 @@ static size_t ipip_get_size(const struct net_device *dev)
427504
nla_total_size(1) +
428505
/* IFLA_IPTUN_TOS */
429506
nla_total_size(1) +
507+
/* IFLA_IPTUN_PROTO */
508+
nla_total_size(1) +
430509
/* IFLA_IPTUN_PMTUDISC */
431510
nla_total_size(1) +
432511
/* IFLA_IPTUN_ENCAP_TYPE */
@@ -450,6 +529,7 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
450529
nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
451530
nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
452531
nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
532+
nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
453533
nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
454534
!!(parm->iph.frag_off & htons(IP_DF))))
455535
goto nla_put_failure;
@@ -476,6 +556,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
476556
[IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
477557
[IFLA_IPTUN_TTL] = { .type = NLA_U8 },
478558
[IFLA_IPTUN_TOS] = { .type = NLA_U8 },
559+
[IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
479560
[IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
480561
[IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 },
481562
[IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 },
@@ -489,6 +570,7 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly = {
489570
.policy = ipip_policy,
490571
.priv_size = sizeof(struct ip_tunnel),
491572
.setup = ipip_tunnel_setup,
573+
.validate = ipip_tunnel_validate,
492574
.newlink = ipip_newlink,
493575
.changelink = ipip_changelink,
494576
.dellink = ip_tunnel_dellink,
@@ -503,6 +585,14 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
503585
.priority = 1,
504586
};
505587

588+
#if IS_ENABLED(CONFIG_MPLS)
589+
static struct xfrm_tunnel mplsip_handler __read_mostly = {
590+
.handler = mplsip_rcv,
591+
.err_handler = ipip_err,
592+
.priority = 1,
593+
};
594+
#endif
595+
506596
static int __net_init ipip_init_net(struct net *net)
507597
{
508598
return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
@@ -525,16 +615,23 @@ static int __init ipip_init(void)
525615
{
526616
int err;
527617

528-
pr_info("ipip: IPv4 over IPv4 tunneling driver\n");
618+
pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
529619

530620
err = register_pernet_device(&ipip_net_ops);
531621
if (err < 0)
532622
return err;
533623
err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
534624
if (err < 0) {
535625
pr_info("%s: can't register tunnel\n", __func__);
536-
goto xfrm_tunnel_failed;
626+
goto xfrm_tunnel_ipip_failed;
627+
}
628+
#if IS_ENABLED(CONFIG_MPLS)
629+
err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
630+
if (err < 0) {
631+
pr_info("%s: can't register tunnel\n", __func__);
632+
goto xfrm_tunnel_mplsip_failed;
537633
}
634+
#endif
538635
err = rtnl_link_register(&ipip_link_ops);
539636
if (err < 0)
540637
goto rtnl_link_failed;
@@ -543,8 +640,13 @@ static int __init ipip_init(void)
543640
return err;
544641

545642
rtnl_link_failed:
643+
#if IS_ENABLED(CONFIG_MPLS)
644+
xfrm4_tunnel_deregister(&mplsip_handler, AF_INET);
645+
xfrm_tunnel_mplsip_failed:
646+
647+
#endif
546648
xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
547-
xfrm_tunnel_failed:
649+
xfrm_tunnel_ipip_failed:
548650
unregister_pernet_device(&ipip_net_ops);
549651
goto out;
550652
}
@@ -554,7 +656,10 @@ static void __exit ipip_fini(void)
554656
rtnl_link_unregister(&ipip_link_ops);
555657
if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
556658
pr_info("%s: can't deregister tunnel\n", __func__);
557-
659+
#if IS_ENABLED(CONFIG_MPLS)
660+
if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
661+
pr_info("%s: can't deregister tunnel\n", __func__);
662+
#endif
558663
unregister_pernet_device(&ipip_net_ops);
559664
}
560665

0 commit comments

Comments
 (0)