Skip to content

Commit 6c8702c

Browse files
David Lebrundavem330
David Lebrun
authored andcommitted
ipv6: sr: add support for SRH encapsulation and injection with lwtunnels
This patch creates a new type of interfaceless lightweight tunnel (SEG6), enabling the encapsulation and injection of SRH within locally emitted packets and forwarded packets. >From a configuration viewpoint, a seg6 tunnel would be configured as follows: ip -6 ro ad fc00::1/128 encap seg6 mode encap segs fc42::1,fc42::2,fc42::3 dev eth0 Any packet whose destination address is fc00::1 would thus be encapsulated within an outer IPv6 header containing the SRH with three segments, and would actually be routed to the first segment of the list. If `mode inline' was specified instead of `mode encap', then the SRH would be directly inserted after the IPv6 header without outer encapsulation. The inline mode is only available if CONFIG_IPV6_SEG6_INLINE is enabled. This feature was made configurable because direct header insertion may break several mechanisms such as PMTUD or IPSec AH. Signed-off-by: David Lebrun <david.lebrun@uclouvain.be> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 915d7e5 commit 6c8702c

File tree

9 files changed

+526
-1
lines changed

9 files changed

+526
-1
lines changed

include/linux/seg6_iptunnel.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef _LINUX_SEG6_IPTUNNEL_H
2+
#define _LINUX_SEG6_IPTUNNEL_H
3+
4+
#include <uapi/linux/seg6_iptunnel.h>
5+
6+
#endif

include/net/seg6.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#include <linux/net.h>
1818
#include <linux/ipv6.h>
19+
#include <net/lwtunnel.h>
20+
#include <linux/seg6.h>
1921

2022
static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
2123
__be32 to)
@@ -48,5 +50,9 @@ static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
4850

4951
extern int seg6_init(void);
5052
extern void seg6_exit(void);
53+
extern int seg6_iptunnel_init(void);
54+
extern void seg6_iptunnel_exit(void);
55+
56+
extern bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len);
5157

5258
#endif

include/uapi/linux/lwtunnel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ enum lwtunnel_encap_types {
99
LWTUNNEL_ENCAP_IP,
1010
LWTUNNEL_ENCAP_ILA,
1111
LWTUNNEL_ENCAP_IP6,
12+
LWTUNNEL_ENCAP_SEG6,
1213
__LWTUNNEL_ENCAP_MAX,
1314
};
1415

include/uapi/linux/seg6_iptunnel.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* SR-IPv6 implementation
3+
*
4+
* Author:
5+
* David Lebrun <david.lebrun@uclouvain.be>
6+
*
7+
*
8+
* This program is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU General Public License
10+
* as published by the Free Software Foundation; either version
11+
* 2 of the License, or (at your option) any later version.
12+
*/
13+
14+
#ifndef _UAPI_LINUX_SEG6_IPTUNNEL_H
15+
#define _UAPI_LINUX_SEG6_IPTUNNEL_H
16+
17+
enum {
18+
SEG6_IPTUNNEL_UNSPEC,
19+
SEG6_IPTUNNEL_SRH,
20+
__SEG6_IPTUNNEL_MAX,
21+
};
22+
#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
23+
24+
struct seg6_iptunnel_encap {
25+
int mode;
26+
struct ipv6_sr_hdr srh[0];
27+
};
28+
29+
#define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
30+
31+
enum {
32+
SEG6_IPTUN_MODE_INLINE,
33+
SEG6_IPTUN_MODE_ENCAP,
34+
};
35+
36+
static inline size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
37+
{
38+
int encap = (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP);
39+
40+
return ((tuninfo->srh->hdrlen + 1) << 3) +
41+
(encap * sizeof(struct ipv6hdr));
42+
}
43+
44+
#endif

net/core/lwtunnel.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
3939
return "MPLS";
4040
case LWTUNNEL_ENCAP_ILA:
4141
return "ILA";
42+
case LWTUNNEL_ENCAP_SEG6:
43+
return "SEG6";
4244
case LWTUNNEL_ENCAP_IP6:
4345
case LWTUNNEL_ENCAP_IP:
4446
case LWTUNNEL_ENCAP_NONE:

net/ipv6/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,4 +289,16 @@ config IPV6_PIMSM_V2
289289
Support for IPv6 PIM multicast routing protocol PIM-SMv2.
290290
If unsure, say N.
291291

292+
config IPV6_SEG6_INLINE
293+
bool "IPv6: direct Segment Routing Header insertion "
294+
depends on IPV6
295+
---help---
296+
Support for direct insertion of the Segment Routing Header,
297+
also known as inline mode. Be aware that direct insertion of
298+
extension headers (as opposed to encapsulation) may break
299+
multiple mechanisms such as PMTUD or IPSec AH. Use this feature
300+
only if you know exactly what you are doing.
301+
302+
If unsure, say N.
303+
292304
endif # IPV6

net/ipv6/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
99
route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \
1010
raw.o icmp.o mcast.o reassembly.o tcp_ipv6.o ping.o \
1111
exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o \
12-
udp_offload.o seg6.o
12+
udp_offload.o seg6.o seg6_iptunnel.o
1313

1414
ipv6-offload := ip6_offload.o tcpv6_offload.o exthdrs_offload.o
1515

net/ipv6/seg6.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,43 @@
2626
#include <linux/seg6.h>
2727
#include <linux/seg6_genl.h>
2828

29+
bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
30+
{
31+
int trailing;
32+
unsigned int tlv_offset;
33+
34+
if (srh->type != IPV6_SRCRT_TYPE_4)
35+
return false;
36+
37+
if (((srh->hdrlen + 1) << 3) != len)
38+
return false;
39+
40+
if (srh->segments_left != srh->first_segment)
41+
return false;
42+
43+
tlv_offset = sizeof(*srh) + ((srh->first_segment + 1) << 4);
44+
45+
trailing = len - tlv_offset;
46+
if (trailing < 0)
47+
return false;
48+
49+
while (trailing) {
50+
struct sr6_tlv *tlv;
51+
unsigned int tlv_len;
52+
53+
tlv = (struct sr6_tlv *)((unsigned char *)srh + tlv_offset);
54+
tlv_len = sizeof(*tlv) + tlv->len;
55+
56+
trailing -= tlv_len;
57+
if (trailing < 0)
58+
return false;
59+
60+
tlv_offset += tlv_len;
61+
}
62+
63+
return true;
64+
}
65+
2966
static struct genl_family seg6_genl_family;
3067

3168
static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
@@ -198,17 +235,24 @@ int __init seg6_init(void)
198235
if (err)
199236
goto out_unregister_genl;
200237

238+
err = seg6_iptunnel_init();
239+
if (err)
240+
goto out_unregister_pernet;
241+
201242
pr_info("Segment Routing with IPv6\n");
202243

203244
out:
204245
return err;
246+
out_unregister_pernet:
247+
unregister_pernet_subsys(&ip6_segments_ops);
205248
out_unregister_genl:
206249
genl_unregister_family(&seg6_genl_family);
207250
goto out;
208251
}
209252

210253
void seg6_exit(void)
211254
{
255+
seg6_iptunnel_exit();
212256
unregister_pernet_subsys(&ip6_segments_ops);
213257
genl_unregister_family(&seg6_genl_family);
214258
}

0 commit comments

Comments
 (0)