2 * mpls tunnels An implementation mpls tunnels using the light weight tunnel
5 * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
13 #include <linux/types.h>
14 #include <linux/skbuff.h>
15 #include <linux/net.h>
16 #include <linux/module.h>
17 #include <linux/mpls.h>
18 #include <linux/vmalloc.h>
21 #include <net/lwtunnel.h>
22 #include <net/netevent.h>
23 #include <net/netns/generic.h>
24 #include <net/ip6_fib.h>
25 #include <net/route.h>
26 #include <net/mpls_iptunnel.h>
27 #include <linux/mpls_iptunnel.h>
30 static const struct nla_policy mpls_iptunnel_policy
[MPLS_IPTUNNEL_MAX
+ 1] = {
31 [MPLS_IPTUNNEL_DST
] = { .type
= NLA_U32
},
34 static unsigned int mpls_encap_size(struct mpls_iptunnel_encap
*en
)
36 /* The size of the layer 2.5 labels to be added for this route */
37 return en
->labels
* sizeof(struct mpls_shim_hdr
);
40 static int mpls_xmit(struct sk_buff
*skb
)
42 struct mpls_iptunnel_encap
*tun_encap_info
;
43 struct mpls_shim_hdr
*hdr
;
44 struct net_device
*out_dev
;
46 unsigned int new_header_size
;
48 struct dst_entry
*dst
= skb_dst(skb
);
49 struct rtable
*rt
= NULL
;
50 struct rt6_info
*rt6
= NULL
;
51 struct mpls_dev
*out_mdev
;
57 /* Find the output device */
61 if (dst
->ops
->family
== AF_INET
) {
62 ttl
= ip_hdr(skb
)->ttl
;
63 rt
= (struct rtable
*)dst
;
64 } else if (dst
->ops
->family
== AF_INET6
) {
65 ttl
= ipv6_hdr(skb
)->hop_limit
;
66 rt6
= (struct rt6_info
*)dst
;
73 if (!mpls_output_possible(out_dev
) ||
74 !dst
->lwtstate
|| skb_warn_if_lro(skb
))
77 skb_forward_csum(skb
);
79 tun_encap_info
= mpls_lwtunnel_encap(dst
->lwtstate
);
81 /* Verify the destination can hold the packet */
82 new_header_size
= mpls_encap_size(tun_encap_info
);
83 mtu
= mpls_dev_mtu(out_dev
);
84 if (mpls_pkt_too_big(skb
, mtu
- new_header_size
))
87 hh_len
= LL_RESERVED_SPACE(out_dev
);
88 if (!out_dev
->header_ops
)
91 /* Ensure there is enough space for the headers in the skb */
92 if (skb_cow(skb
, hh_len
+ new_header_size
))
95 skb_set_inner_protocol(skb
, skb
->protocol
);
96 skb_reset_inner_network_header(skb
);
98 skb_push(skb
, new_header_size
);
100 skb_reset_network_header(skb
);
103 skb
->protocol
= htons(ETH_P_MPLS_UC
);
105 /* Push the new labels */
108 for (i
= tun_encap_info
->labels
- 1; i
>= 0; i
--) {
109 hdr
[i
] = mpls_entry_encode(tun_encap_info
->label
[i
],
114 mpls_stats_inc_outucastpkts(out_dev
, skb
);
117 err
= neigh_xmit(NEIGH_ARP_TABLE
, out_dev
, &rt
->rt_gateway
,
120 err
= neigh_xmit(NEIGH_ND_TABLE
, out_dev
, &rt6
->rt6i_gateway
,
123 net_dbg_ratelimited("%s: packet transmission failed: %d\n",
126 return LWTUNNEL_XMIT_DONE
;
129 out_mdev
= out_dev
? mpls_dev_get(out_dev
) : NULL
;
131 MPLS_INC_STATS(out_mdev
, tx_errors
);
136 static int mpls_build_state(struct nlattr
*nla
,
137 unsigned int family
, const void *cfg
,
138 struct lwtunnel_state
**ts
)
140 struct mpls_iptunnel_encap
*tun_encap_info
;
141 struct nlattr
*tb
[MPLS_IPTUNNEL_MAX
+ 1];
142 struct lwtunnel_state
*newts
;
145 ret
= nla_parse_nested(tb
, MPLS_IPTUNNEL_MAX
, nla
,
146 mpls_iptunnel_policy
);
150 if (!tb
[MPLS_IPTUNNEL_DST
])
154 newts
= lwtunnel_state_alloc(sizeof(*tun_encap_info
));
158 tun_encap_info
= mpls_lwtunnel_encap(newts
);
159 ret
= nla_get_labels(tb
[MPLS_IPTUNNEL_DST
], MAX_NEW_LABELS
,
160 &tun_encap_info
->labels
, tun_encap_info
->label
);
163 newts
->type
= LWTUNNEL_ENCAP_MPLS
;
164 newts
->flags
|= LWTUNNEL_STATE_XMIT_REDIRECT
;
165 newts
->headroom
= mpls_encap_size(tun_encap_info
);
178 static int mpls_fill_encap_info(struct sk_buff
*skb
,
179 struct lwtunnel_state
*lwtstate
)
181 struct mpls_iptunnel_encap
*tun_encap_info
;
183 tun_encap_info
= mpls_lwtunnel_encap(lwtstate
);
185 if (nla_put_labels(skb
, MPLS_IPTUNNEL_DST
, tun_encap_info
->labels
,
186 tun_encap_info
->label
))
187 goto nla_put_failure
;
195 static int mpls_encap_nlsize(struct lwtunnel_state
*lwtstate
)
197 struct mpls_iptunnel_encap
*tun_encap_info
;
199 tun_encap_info
= mpls_lwtunnel_encap(lwtstate
);
201 return nla_total_size(tun_encap_info
->labels
* 4);
204 static int mpls_encap_cmp(struct lwtunnel_state
*a
, struct lwtunnel_state
*b
)
206 struct mpls_iptunnel_encap
*a_hdr
= mpls_lwtunnel_encap(a
);
207 struct mpls_iptunnel_encap
*b_hdr
= mpls_lwtunnel_encap(b
);
210 if (a_hdr
->labels
!= b_hdr
->labels
)
213 for (l
= 0; l
< MAX_NEW_LABELS
; l
++)
214 if (a_hdr
->label
[l
] != b_hdr
->label
[l
])
219 static const struct lwtunnel_encap_ops mpls_iptun_ops
= {
220 .build_state
= mpls_build_state
,
222 .fill_encap
= mpls_fill_encap_info
,
223 .get_encap_size
= mpls_encap_nlsize
,
224 .cmp_encap
= mpls_encap_cmp
,
225 .owner
= THIS_MODULE
,
228 static int __init
mpls_iptunnel_init(void)
230 return lwtunnel_encap_add_ops(&mpls_iptun_ops
, LWTUNNEL_ENCAP_MPLS
);
232 module_init(mpls_iptunnel_init
);
234 static void __exit
mpls_iptunnel_exit(void)
236 lwtunnel_encap_del_ops(&mpls_iptun_ops
, LWTUNNEL_ENCAP_MPLS
);
238 module_exit(mpls_iptunnel_exit
);
240 MODULE_ALIAS_RTNL_LWT(MPLS
);
241 MODULE_DESCRIPTION("MultiProtocol Label Switching IP Tunnels");
242 MODULE_LICENSE("GPL v2");