netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/9] add support for IPv6 Segment Routing
@ 2016-08-26 15:52 David Lebrun
  2016-08-26 15:52 ` [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header) David Lebrun
                   ` (8 more replies)
  0 siblings, 9 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:52 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

Segment Routing (SR) is a source routing paradigm, architecturally
defined in draft-ietf-spring-segment-routing-09 [1]. The IPv6 flavor of
SR is defined in draft-ietf-6man-segment-routing-header-01 [2].

The main idea is that an SR-enabled packet contains a list of segments,
which represent mandatory waypoints. Each waypoint is called a segment
endpoint. The SR-enabled packet is routed normally (e.g. shortest path)
between the segment endpoints. A node that inserts an SRH into a packet
is called an ingress node, and a node that is the last segment endpoint
is called an egress node.

>From an IPv6 viewpoint, an SR-enabled packet contains an IPv6 extension
header, which is a Routing Header type 4, defined as follows:

struct ipv6_sr_hdr {
        __u8    nexthdr;
        __u8    hdrlen;
        __u8    type;
        __u8    segments_left;
        __u8    first_segment;
        __be16  flags;
        __u8    reserved;

        struct in6_addr segments[0];
} __attribute__((packed));

The first 4 bytes of the SRH is consistent with the Routing Header
definition in RFC 2460. The type is set to `4' (SRH).

Each segment is encoded as an IPv6 address. The segments are encoded in
reverse order: segments[0] is the last segment of the path, and
segments[first_segment] is the first segment of the path.

segments[segments_left] points to the currently active segment and
segments_left is decremented at each segment endpoint.

There exist two ways for a packet to receive an SRH, we call them
encap mode and inline mode. In the encap mode, the packet is encapsulated
in an outer IPv6 header that contains the SRH. The inner (original) packet
is not modified. A virtual tunnel is thus created between the ingress node
(the node that encapsulates) and the egress node (the last segment of the path).
Once an encapsulated SR packet reaches the egress node, the node decapsulates
the packet and performs a routing decision on the inner packet. This kind of
SRH insertion is intended to use for routers that encapsulates in-transit
packet.

The second SRH insertion method, the inline mode, acts by directly inserting
the SRH right after the IPv6 header of the original packet. For this method,
if a particular flag (SR6_FLAG_CLEANUP) is set, then the penultimate segment
endpoint must strip the SRH from the packet before forwarding it to the last
segment endpoint. This insertion method is intended to use for endhosts,
however it is also used for in-transit packets by some industry actors.

Finally, the SRH may contain TLVs after the segments list. Several types of
TLVs are defined, but we currently consider only the HMAC TLV. This TLV is
an answer to the deprecation of the RH0 and enables to ensure the authenticity
and integrity of the SRH. The HMAC text contains the flags, the first_segment
index, the full list of segments, and the source address of the packet. While
SR is intended to use mostly within a single administrative domain, the HMAC
TLV allows to verify SR packets coming from an untrusted source.

This patches series implements support for the IPv6 flavor of SR and is
logically divided into the following components:

	(1) Data plane support (patch 01). This patch adds a function
	    in net/ipv6/exthdrs.c to handle the Routing Header type 4.
	    It enables the kernel to act as a segment endpoint, by supporting
	    the following operations: decrementation of the segments_left field,
	    cleanup flag support (removal of the SRH if we are the penultimate
	    segment endpoint) and decapsulation of the inner packet as an egress
	    node.
	(2) Control plane support (patches 02-04 and 08-09). These patches enables
	    to insert SRH on locally emitted and/or forwarded packets, both with
	    encap mode and with inline mode. The SRH insertion is controlled through
	    the lightweight tunnels mechanism. Furthermore, patch 09 enables the
	    applications to insert an SRH on a per-socket basis, through the
	    setsockopt() system call. The mechanism to specify a per-socket
	    Routing Header was already defined for RH0 and no special modification
	    was performed on this side. However, the code to actually push the RH
	    onto the packets had to be adapted for the SRH specifications.
	(3) HMAC support (patches 05-07). These patches adds the support of the
	    HMAC TLV verification for the dataplane part, and generation for
	    the control plane part. Two hashing algorithms are supported
	    (SHA-1 as legacy and SHA-256 as required by the IETF draft), but
	    additional algorithms can be easily supported by simply adding an
	    entry into an array.

[1] https://tools.ietf.org/html/draft-ietf-spring-segment-routing-09
[2] https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-01

Any comment on the architecture, API and implementation would be very welcome.

Regards,

David Lebrun (9):
  ipv6: implement dataplane support for rthdr type 4 (Segment Routing
    Header)
  ipv6: sr: add code base for control plane support of SR-IPv6
  ipv6: route: export symbol ip6_route_input
  ipv6: sr: add support for SRH encapsulation and injection with
    lwtunnels
  ipv6: sr: add core files for SR HMAC support
  ipv6: sr: implement API to control SR HMAC structures
  ipv6: sr: add calls to verify and insert HMAC signatures
  ipv6: add source address argument for ipv6_push_nfrag_opts
  ipv6: sr: add support for SRH injection through setsockopt

 include/linux/ipv6.h               |   6 +
 include/linux/seg6.h               |   6 +
 include/linux/seg6_genl.h          |   6 +
 include/linux/seg6_hmac.h          |   6 +
 include/linux/seg6_iptunnel.h      |   6 +
 include/net/ipv6.h                 |   3 +-
 include/net/netns/ipv6.h           |   3 +
 include/net/seg6.h                 |  64 ++++++
 include/net/seg6_hmac.h            |  62 ++++++
 include/uapi/linux/ipv6.h          |   3 +
 include/uapi/linux/lwtunnel.h      |   1 +
 include/uapi/linux/seg6.h          |  46 ++++
 include/uapi/linux/seg6_genl.h     |  32 +++
 include/uapi/linux/seg6_hmac.h     |  20 ++
 include/uapi/linux/seg6_iptunnel.h |  33 +++
 net/core/lwtunnel.c                |   2 +
 net/ipv6/Kconfig                   |  38 ++++
 net/ipv6/Makefile                  |   3 +
 net/ipv6/addrconf.c                |  36 ++++
 net/ipv6/exthdrs.c                 | 225 ++++++++++++++++++-
 net/ipv6/ip6_output.c              |   5 +-
 net/ipv6/ip6_tunnel.c              |   2 +-
 net/ipv6/ipv6_sockglue.c           |   4 +
 net/ipv6/route.c                   |   1 +
 net/ipv6/seg6.c                    | 391 +++++++++++++++++++++++++++++++++
 net/ipv6/seg6_hmac.c               | 432 +++++++++++++++++++++++++++++++++++++
 net/ipv6/seg6_iptunnel.c           | 330 ++++++++++++++++++++++++++++
 27 files changed, 1756 insertions(+), 10 deletions(-)
 create mode 100644 include/linux/seg6.h
 create mode 100644 include/linux/seg6_genl.h
 create mode 100644 include/linux/seg6_hmac.h
 create mode 100644 include/linux/seg6_iptunnel.h
 create mode 100644 include/net/seg6.h
 create mode 100644 include/net/seg6_hmac.h
 create mode 100644 include/uapi/linux/seg6.h
 create mode 100644 include/uapi/linux/seg6_genl.h
 create mode 100644 include/uapi/linux/seg6_hmac.h
 create mode 100644 include/uapi/linux/seg6_iptunnel.h
 create mode 100644 net/ipv6/seg6.c
 create mode 100644 net/ipv6/seg6_hmac.c
 create mode 100644 net/ipv6/seg6_iptunnel.c

-- 
2.3.6

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
@ 2016-08-26 15:52 ` David Lebrun
  2016-08-31 14:51   ` Nicolas Dichtel
  2016-08-31 17:13   ` Stephen Hemminger
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:52 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

Implement minimal support for processing of SR-enabled packets
as described in
https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-01.

This patch implements the following operations:
- Intermediate segment endpoint: incrementation of active segment and rerouting.
- Egress for SR-encapsulated packets: decapsulation of outer IPv6 header + SRH
  and routing of inner packet.
- Cleanup flag support for SR-inlined packets: removal of SRH if we are the
  penultimate segment endpoint.

A per-interface sysctl seg6_enabled is provided, to accept/deny SR-enabled
packets. Default is deny.

This patch does not provide support for HMAC-signed packets.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 include/linux/ipv6.h      |   3 +
 include/linux/seg6.h      |   6 ++
 include/uapi/linux/ipv6.h |   2 +
 include/uapi/linux/seg6.h |  46 +++++++++++++++
 net/ipv6/Kconfig          |  11 ++++
 net/ipv6/addrconf.c       |  18 ++++++
 net/ipv6/exthdrs.c        | 142 ++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 228 insertions(+)
 create mode 100644 include/linux/seg6.h
 create mode 100644 include/uapi/linux/seg6.h

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index c6dbcd8..d3d8bd5 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -63,6 +63,9 @@ struct ipv6_devconf {
 	} stable_secret;
 	__s32		use_oif_addrs_only;
 	__s32		keep_addr_on_down;
+#ifdef CONFIG_IPV6_SEG6
+	__s32		seg6_enabled;
+#endif
 
 	struct ctl_table_header *sysctl_header;
 };
diff --git a/include/linux/seg6.h b/include/linux/seg6.h
new file mode 100644
index 0000000..7a66d2b
--- /dev/null
+++ b/include/linux/seg6.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_SEG6_H
+#define _LINUX_SEG6_H
+
+#include <uapi/linux/seg6.h>
+
+#endif
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 3958760..a4addc8 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -39,6 +39,7 @@ struct in6_ifreq {
 #define IPV6_SRCRT_STRICT	0x01	/* Deprecated; will be removed */
 #define IPV6_SRCRT_TYPE_0	0	/* Deprecated; will be removed */
 #define IPV6_SRCRT_TYPE_2	2	/* IPv6 type 2 Routing Header	*/
+#define IPV6_SRCRT_TYPE_4	4	/* Segment Routing with IPv6 */
 
 /*
  *	routing header
@@ -177,6 +178,7 @@ enum {
 	DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
 	DEVCONF_DROP_UNSOLICITED_NA,
 	DEVCONF_KEEP_ADDR_ON_DOWN,
+	DEVCONF_SEG6_ENABLED,
 	DEVCONF_MAX
 };
 
diff --git a/include/uapi/linux/seg6.h b/include/uapi/linux/seg6.h
new file mode 100644
index 0000000..9f9e157
--- /dev/null
+++ b/include/uapi/linux/seg6.h
@@ -0,0 +1,46 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_SEG6_H
+#define _UAPI_LINUX_SEG6_H
+
+/*
+ * SRH
+ */
+struct ipv6_sr_hdr {
+	__u8	nexthdr;
+	__u8	hdrlen;
+	__u8	type;
+	__u8	segments_left;
+	__u8	first_segment;
+	__be16	flags;
+	__u8	reserved;
+
+	struct in6_addr segments[0];
+} __attribute__((packed));
+
+#define SR6_FLAG_CLEANUP	(1 << 15)
+#define SR6_FLAG_PROTECTED	(1 << 14)
+#define SR6_FLAG_OAM		(1 << 13)
+#define SR6_FLAG_ALERT		(1 << 12)
+#define SR6_FLAG_HMAC		(1 << 11)
+
+#define SR6_TLV_INGRESS		1
+#define SR6_TLV_EGRESS		2
+#define SR6_TLV_OPAQUE		3
+#define SR6_TLV_PADDING		4
+#define SR6_TLV_HMAC		5
+
+#define sr_get_flags(srh) (be16_to_cpu((srh)->flags))
+
+#endif
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 2343e4f..98ecc1d 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -289,4 +289,15 @@ config IPV6_PIMSM_V2
 	  Support for IPv6 PIM multicast routing protocol PIM-SMv2.
 	  If unsure, say N.
 
+config IPV6_SEG6
+	bool "IPv6: Segment Routing support"
+	depends on IPV6
+	---help---
+	  Experimental support for IPv6 Segment Routing dataplane as defined
+	  in IETF draft-ietf-6man-segment-routing-header-01. This option
+	  enables the processing of SR-enabled packets allowing the kernel
+	  to act as a segment endpoint (intermediate or egress).
+
+	  If unsure, say N.
+
 endif # IPV6
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index df8425f..9cc7dac 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -217,6 +217,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
 	.use_oif_addrs_only	= 0,
 	.ignore_routes_with_linkdown = 0,
 	.keep_addr_on_down	= 0,
+#ifdef CONFIG_IPV6_SEG6
+	.seg6_enabled		= 0,
+#endif
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -262,6 +265,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 	.use_oif_addrs_only	= 0,
 	.ignore_routes_with_linkdown = 0,
 	.keep_addr_on_down	= 0,
+#ifdef CONFIG_IPV6_SEG6
+	.seg6_enabled		= 0,
+#endif
 };
 
 /* Check if a valid qdisc is available */
@@ -4920,6 +4926,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 	array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast;
 	array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na;
 	array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
+#ifdef CONFIG_IPV6_SEG6
+	array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled;
+#endif
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -6009,6 +6018,15 @@ static const struct ctl_table addrconf_sysctl[] = {
 		.proc_handler	= proc_dointvec,
 
 	},
+#ifdef CONFIG_IPV6_SEG6
+	{
+		.procname	= "seg6_enabled",
+		.data		= &ipv6_devconf.seg6_enabled,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+#endif
 	{
 		/* sentinel */
 	}
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 139ceb6..e6f41fc 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -47,6 +47,9 @@
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
 #include <net/xfrm.h>
 #endif
+#ifdef CONFIG_IPV6_SEG6
+#include <linux/seg6.h>
+#endif
 
 #include <linux/uaccess.h>
 
@@ -286,6 +289,139 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
 	return -1;
 }
 
+#ifdef CONFIG_IPV6_SEG6
+static int ipv6_srh_rcv(struct sk_buff *skb)
+{
+	struct inet6_skb_parm *opt = IP6CB(skb);
+	struct in6_addr *addr = NULL, *last_addr = NULL, *active_addr = NULL;
+	struct ipv6_sr_hdr *hdr;
+	struct net *net = dev_net(skb->dev);
+	int cleanup = 0;
+	struct inet6_dev *idev;
+	int accept_seg6;
+
+	hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
+
+	idev = __in6_dev_get(skb->dev);
+
+	accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
+	if (accept_seg6 > idev->cnf.seg6_enabled)
+		accept_seg6 = idev->cnf.seg6_enabled;
+
+	if (!accept_seg6) {
+		kfree_skb(skb);
+		return -1;
+	}
+
+looped_back:
+	last_addr = hdr->segments;
+
+	if (hdr->segments_left > 0) {
+		if (hdr->nexthdr != NEXTHDR_IPV6 && hdr->segments_left == 1 &&
+		    sr_get_flags(hdr) & SR6_FLAG_CLEANUP)
+			cleanup = 1;
+	} else {
+		if (hdr->nexthdr == NEXTHDR_IPV6) {
+			int offset = (hdr->hdrlen + 1) << 3;
+
+			if (!pskb_pull(skb, offset)) {
+				kfree_skb(skb);
+				return -1;
+			}
+			skb_postpull_rcsum(skb, skb_transport_header(skb),
+					   offset);
+
+			skb_reset_network_header(skb);
+			skb_reset_transport_header(skb);
+			skb->encapsulation = 0;
+
+			__skb_tunnel_rx(skb, skb->dev, net);
+
+			netif_rx(skb);
+			return -1;
+		}
+
+		opt->srcrt = skb_network_header_len(skb);
+		opt->lastopt = opt->srcrt;
+		skb->transport_header += (hdr->hdrlen + 1) << 3;
+		opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
+
+		return 1;
+	}
+
+	if (skb_cloned(skb)) {
+		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+			__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
+					IPSTATS_MIB_OUTDISCARDS);
+			kfree_skb(skb);
+			return -1;
+		}
+	}
+
+	if (skb->ip_summed == CHECKSUM_COMPLETE)
+		skb->ip_summed = CHECKSUM_NONE;
+
+	hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
+
+	active_addr = hdr->segments + hdr->segments_left;
+	hdr->segments_left--;
+	addr = hdr->segments + hdr->segments_left;
+
+	ipv6_hdr(skb)->daddr = *addr;
+
+	skb_push(skb, sizeof(struct ipv6hdr));
+
+	/* cleanup */
+
+	if (cleanup) {
+		int srhlen = (hdr->hdrlen + 1) << 3;
+		int nh = hdr->nexthdr;
+
+		memmove(skb_network_header(skb) + srhlen,
+			skb_network_header(skb),
+			(unsigned char *)hdr - skb_network_header(skb));
+		skb_pull(skb, srhlen);
+		skb->network_header += srhlen;
+		ipv6_hdr(skb)->nexthdr = nh;
+		ipv6_hdr(skb)->payload_len = htons(skb->len -
+						   sizeof(struct ipv6hdr));
+	}
+
+	skb_dst_drop(skb);
+
+	ip6_route_input(skb);
+
+	if (skb_dst(skb)->error) {
+		dst_input(skb);
+		return -1;
+	}
+
+	if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
+		if (ipv6_hdr(skb)->hop_limit <= 1) {
+			__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
+					IPSTATS_MIB_INHDRERRORS);
+			icmpv6_send(skb, ICMPV6_TIME_EXCEED,
+				    ICMPV6_EXC_HOPLIMIT, 0);
+			kfree_skb(skb);
+			return -1;
+		}
+		ipv6_hdr(skb)->hop_limit--;
+
+		/* be sure that srh is still present before reinjecting */
+		if (!cleanup) {
+			skb_pull(skb, sizeof(struct ipv6hdr));
+			goto looped_back;
+		}
+		skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+		IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
+	}
+
+	dst_input(skb);
+
+	return -1;
+}
+#endif
+
 /********************************
   Routing header.
  ********************************/
@@ -326,6 +462,12 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
 		return -1;
 	}
 
+#ifdef CONFIG_IPV6_SEG6
+	/* segment routing */
+	if (hdr->type == IPV6_SRCRT_TYPE_4)
+		return ipv6_srh_rcv(skb);
+#endif
+
 looped_back:
 	if (hdr->segments_left == 0) {
 		switch (hdr->type) {
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
  2016-08-26 15:52 ` [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header) David Lebrun
@ 2016-08-26 15:52 ` David Lebrun
  2016-08-29 15:31   ` Roopa Prabhu
                     ` (4 more replies)
  2016-08-26 15:52 ` [RFC 3/9] ipv6: route: export symbol ip6_route_input David Lebrun
                   ` (6 subsequent siblings)
  8 siblings, 5 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:52 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

This patch adds the necessary hooks and structures to provide support
for SR-IPv6 control plane, essentially the Generic Netlink commands
that will be used for userspace control over the Segment Routing
kernel structures.

The genetlink commands provide control over two different structures:
tunnel source and HMAC data. The tunnel source is the source address
that will be used by default when encapsulating packets into an
outer IPv6 header + SRH. If the tunnel source is set to :: then an
address of the outgoing interface will be selected as the source.

The HMAC commands currently just return ENOTSUPP and will be implemented
in a future patch.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 include/linux/seg6_genl.h      |   6 ++
 include/net/netns/ipv6.h       |   3 +
 include/net/seg6.h             |  43 +++++++++
 include/uapi/linux/seg6_genl.h |  32 +++++++
 net/ipv6/Kconfig               |  10 ++
 net/ipv6/Makefile              |   1 +
 net/ipv6/seg6.c                | 212 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 307 insertions(+)
 create mode 100644 include/linux/seg6_genl.h
 create mode 100644 include/net/seg6.h
 create mode 100644 include/uapi/linux/seg6_genl.h
 create mode 100644 net/ipv6/seg6.c

diff --git a/include/linux/seg6_genl.h b/include/linux/seg6_genl.h
new file mode 100644
index 0000000..d6c3fb4f
--- /dev/null
+++ b/include/linux/seg6_genl.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_SEG6_GENL_H
+#define _LINUX_SEG6_GENL_H
+
+#include <uapi/linux/seg6_genl.h>
+
+#endif
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 10d0848..892ed4c 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -85,6 +85,9 @@ struct netns_ipv6 {
 #endif
 	atomic_t		dev_addr_genid;
 	atomic_t		fib6_sernum;
+#if IS_ENABLED(CONFIG_IPV6_SEG6_CORE)
+	struct seg6_pernet_data	*seg6_data;
+#endif
 };
 
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
diff --git a/include/net/seg6.h b/include/net/seg6.h
new file mode 100644
index 0000000..d5177a9
--- /dev/null
+++ b/include/net/seg6.h
@@ -0,0 +1,43 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_SEG6_H
+#define _NET_SEG6_H
+
+#include <linux/net.h>
+#include <linux/ipv6.h>
+
+#define SEG6_VERSION_MAJOR	0
+#define SEG6_VERSION_MINOR	30
+
+struct seg6_pernet_data {
+	spinlock_t lock;
+	struct in6_addr __rcu *tun_src;
+};
+
+static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
+{
+	return net->ipv6.seg6_data;
+}
+
+static inline void seg6_pernet_lock(struct net *net)
+{
+	spin_lock(&seg6_pernet(net)->lock);
+}
+
+static inline void seg6_pernet_unlock(struct net *net)
+{
+	spin_unlock(&seg6_pernet(net)->lock);
+}
+
+#endif
diff --git a/include/uapi/linux/seg6_genl.h b/include/uapi/linux/seg6_genl.h
new file mode 100644
index 0000000..fcf1c60
--- /dev/null
+++ b/include/uapi/linux/seg6_genl.h
@@ -0,0 +1,32 @@
+#ifndef _UAPI_LINUX_SEG6_GENL_H
+#define _UAPI_LINUX_SEG6_GENL_H
+
+#define SEG6_GENL_NAME		"SEG6"
+#define SEG6_GENL_VERSION	0x1
+
+enum {
+	SEG6_ATTR_UNSPEC,
+	SEG6_ATTR_DST,
+	SEG6_ATTR_DSTLEN,
+	SEG6_ATTR_HMACKEYID,
+	SEG6_ATTR_SECRET,
+	SEG6_ATTR_SECRETLEN,
+	SEG6_ATTR_ALGID,
+	SEG6_ATTR_HMACINFO,
+	__SEG6_ATTR_MAX,
+};
+
+#define SEG6_ATTR_MAX (__SEG6_ATTR_MAX - 1)
+
+enum {
+	SEG6_CMD_UNSPEC,
+	SEG6_CMD_SETHMAC,
+	SEG6_CMD_DUMPHMAC,
+	SEG6_CMD_SET_TUNSRC,
+	SEG6_CMD_GET_TUNSRC,
+	__SEG6_CMD_MAX,
+};
+
+#define SEG6_CMD_MAX (__SEG6_CMD_MAX - 1)
+
+#endif
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 98ecc1d..931111f 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -300,4 +300,14 @@ config IPV6_SEG6
 
 	  If unsure, say N.
 
+config IPV6_SEG6_CORE
+	tristate "IPv6: Segment Routing core control plane support"
+	depends on IPV6_SEG6
+	---help---
+	  Enable the core functionalities required for a control plane support
+	  of SR-IPv6. This option is not useful by itself, it rather provides
+	  the code base for a control plane support.
+
+	  If unsure, say N.
+
 endif # IPV6
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index c174ccb..4254716 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 obj-$(CONFIG_IPV6_FOU) += fou6.o
+obj-$(CONFIG_IPV6_SEG6_CORE) += seg6.o
 
 obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
 obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
new file mode 100644
index 0000000..5b8b4a1
--- /dev/null
+++ b/net/ipv6/seg6.c
@@ -0,0 +1,212 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *	  modify it under the terms of the GNU General Public License
+ *	  as published by the Free Software Foundation; either version
+ *	  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/slab.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+
+#include <net/seg6.h>
+#include <net/genetlink.h>
+#include <linux/seg6.h>
+#include <linux/seg6_genl.h>
+
+static struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
+	[SEG6_ATTR_DST]				= { .type = NLA_BINARY,
+		.len = sizeof(struct in6_addr) },
+	[SEG6_ATTR_DSTLEN]			= { .type = NLA_S32, },
+	[SEG6_ATTR_HMACKEYID]		= { .type = NLA_U32, },
+	[SEG6_ATTR_SECRET]			= { .type = NLA_BINARY, },
+	[SEG6_ATTR_SECRETLEN]		= { .type = NLA_U8, },
+	[SEG6_ATTR_ALGID]			= { .type = NLA_U8, },
+	[SEG6_ATTR_HMACINFO]		= { .type = NLA_NESTED, },
+};
+
+static struct genl_family seg6_genl_family = {
+	.id = GENL_ID_GENERATE,
+	.hdrsize = 0,
+	.name = SEG6_GENL_NAME,
+	.version = SEG6_GENL_VERSION,
+	.maxattr = SEG6_ATTR_MAX,
+	.netnsok = true,
+};
+
+static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
+{
+	return -ENOTSUPP;
+}
+
+static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = genl_info_net(info);
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+	struct in6_addr *val, *t_old, *t_new;
+
+	if (!info->attrs[SEG6_ATTR_DST])
+		return -EINVAL;
+
+	val = (struct in6_addr *)nla_data(info->attrs[SEG6_ATTR_DST]);
+	t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
+
+	seg6_pernet_lock(net);
+
+	t_old = sdata->tun_src;
+	rcu_assign_pointer(sdata->tun_src, t_new);
+
+	seg6_pernet_unlock(net);
+
+	synchronize_net();
+	kfree(t_old);
+
+	return 0;
+}
+
+static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = genl_info_net(info);
+	struct sk_buff *msg;
+	void *hdr;
+	struct in6_addr *tun_src;
+
+	msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+			  &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
+	if (!hdr)
+		goto free_msg;
+
+	rcu_read_lock();
+	tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
+
+	if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
+		goto nla_put_failure;
+
+	rcu_read_unlock();
+
+	genlmsg_end(msg, hdr);
+	genlmsg_reply(msg, info);
+
+	return 0;
+
+nla_put_failure:
+	rcu_read_unlock();
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -ENOMEM;
+}
+
+static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	return -ENOTSUPP;
+}
+
+static struct genl_ops seg6_genl_ops[] = {
+	{
+		.cmd	= SEG6_CMD_SETHMAC,
+		.doit	= seg6_genl_sethmac,
+		.policy	= seg6_genl_policy,
+		.flags	= GENL_ADMIN_PERM,
+	},
+	{
+		.cmd	= SEG6_CMD_DUMPHMAC,
+		.dumpit	= seg6_genl_dumphmac,
+		.policy	= seg6_genl_policy,
+		.flags	= GENL_ADMIN_PERM,
+	},
+	{
+		.cmd	= SEG6_CMD_SET_TUNSRC,
+		.doit	= seg6_genl_set_tunsrc,
+		.policy	= seg6_genl_policy,
+		.flags	= GENL_ADMIN_PERM,
+	},
+	{
+		.cmd	= SEG6_CMD_GET_TUNSRC,
+		.doit	= seg6_genl_get_tunsrc,
+		.policy = seg6_genl_policy,
+		.flags	= GENL_ADMIN_PERM,
+	},
+};
+
+static int __net_init seg6_net_init(struct net *net)
+{
+	struct seg6_pernet_data *sdata;
+
+	sdata = kzalloc(sizeof(*sdata), GFP_KERNEL);
+	if (!sdata)
+		return -ENOMEM;
+
+	spin_lock_init(&sdata->lock);
+
+	sdata->tun_src = kzalloc(sizeof(*sdata->tun_src), GFP_KERNEL);
+	if (!sdata->tun_src) {
+		kfree(sdata);
+		return -ENOMEM;
+	}
+
+	net->ipv6.seg6_data = sdata;
+
+	return 0;
+}
+
+static void __net_exit seg6_net_exit(struct net *net)
+{
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+
+	kfree(sdata->tun_src);
+	kfree(sdata);
+}
+
+static struct pernet_operations ip6_segments_ops = {
+	.init = seg6_net_init,
+	.exit = seg6_net_exit,
+};
+
+static int __init seg6_init(void)
+{
+	int err = -ENOMEM;
+
+	err = genl_register_family_with_ops(&seg6_genl_family, seg6_genl_ops);
+	if (err)
+		goto out;
+
+	err = register_pernet_subsys(&ip6_segments_ops);
+	if (err)
+		goto out_unregister_genl;
+
+	pr_info("SR-IPv6: Release v%d.%d\n", SEG6_VERSION_MAJOR,
+		SEG6_VERSION_MINOR);
+out:
+	return err;
+out_unregister_genl:
+	genl_unregister_family(&seg6_genl_family);
+	goto out;
+}
+module_init(seg6_init);
+
+static void __exit seg6_exit(void)
+{
+	unregister_pernet_subsys(&ip6_segments_ops);
+	genl_unregister_family(&seg6_genl_family);
+}
+module_exit(seg6_exit);
+
+MODULE_DESCRIPTION("Segment Routing with IPv6 core");
+MODULE_LICENSE("GPL v2");
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 3/9] ipv6: route: export symbol ip6_route_input
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
  2016-08-26 15:52 ` [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header) David Lebrun
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
@ 2016-08-26 15:52 ` David Lebrun
  2016-08-26 15:52 ` [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels David Lebrun
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:52 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

The function ip6_route_input() is used in the seg6_iptunnel module
and thus needs to be exported when CONFIG_IPV6_SEG6_IPTUNNEL=m

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 net/ipv6/route.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4981755..7d8d108 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1178,6 +1178,7 @@ void ip6_route_input(struct sk_buff *skb)
 	skb_dst_drop(skb);
 	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
 }
+EXPORT_SYMBOL(ip6_route_input);
 
 static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
 					     struct flowi6 *fl6, int flags)
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
                   ` (2 preceding siblings ...)
  2016-08-26 15:52 ` [RFC 3/9] ipv6: route: export symbol ip6_route_input David Lebrun
@ 2016-08-26 15:52 ` David Lebrun
  2016-08-29 14:52   ` Roopa Prabhu
  2016-08-26 15:54 ` [RFC 5/9] ipv6: sr: add core files for SR HMAC support David Lebrun
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:52 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

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 via <gw> encap seg6 mode encap segs fc42::1,fc42::2,fc42::3

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.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 include/linux/seg6_iptunnel.h      |   6 +
 include/net/seg6.h                 |  11 ++
 include/uapi/linux/lwtunnel.h      |   1 +
 include/uapi/linux/seg6_iptunnel.h |  33 ++++
 net/core/lwtunnel.c                |   2 +
 net/ipv6/Kconfig                   |   9 ++
 net/ipv6/Makefile                  |   1 +
 net/ipv6/seg6_iptunnel.c           | 313 +++++++++++++++++++++++++++++++++++++
 8 files changed, 376 insertions(+)
 create mode 100644 include/linux/seg6_iptunnel.h
 create mode 100644 include/uapi/linux/seg6_iptunnel.h
 create mode 100644 net/ipv6/seg6_iptunnel.c

diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h
new file mode 100644
index 0000000..5377cf6
--- /dev/null
+++ b/include/linux/seg6_iptunnel.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_SEG6_IPTUNNEL_H
+#define _LINUX_SEG6_IPTUNNEL_H
+
+#include <uapi/linux/seg6_iptunnel.h>
+
+#endif
diff --git a/include/net/seg6.h b/include/net/seg6.h
index d5177a9..af817f6 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -16,6 +16,9 @@
 
 #include <linux/net.h>
 #include <linux/ipv6.h>
+#if IS_ENABLED(CONFIG_IPV6_SEG6_IPTUNNEL)
+#include <net/lwtunnel.h>
+#endif
 
 #define SEG6_VERSION_MAJOR	0
 #define SEG6_VERSION_MINOR	30
@@ -40,4 +43,12 @@ static inline void seg6_pernet_unlock(struct net *net)
 	spin_unlock(&seg6_pernet(net)->lock);
 }
 
+#if IS_ENABLED(CONFIG_IPV6_SEG6_IPTUNNEL)
+static inline struct seg6_iptunnel_encap *
+seg6_lwtunnel_encap(struct lwtunnel_state *lwtstate)
+{
+	return (struct seg6_iptunnel_encap *)lwtstate->data;
+}
+#endif
+
 #endif
diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
index a478fe8..453cc62 100644
--- a/include/uapi/linux/lwtunnel.h
+++ b/include/uapi/linux/lwtunnel.h
@@ -9,6 +9,7 @@ enum lwtunnel_encap_types {
 	LWTUNNEL_ENCAP_IP,
 	LWTUNNEL_ENCAP_ILA,
 	LWTUNNEL_ENCAP_IP6,
+	LWTUNNEL_ENCAP_SEG6,
 	__LWTUNNEL_ENCAP_MAX,
 };
 
diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
new file mode 100644
index 0000000..2794a5f
--- /dev/null
+++ b/include/uapi/linux/seg6_iptunnel.h
@@ -0,0 +1,33 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_SEG6_IPTUNNEL_H
+#define _UAPI_LINUX_SEG6_IPTUNNEL_H
+
+enum {
+	SEG6_IPTUNNEL_UNSPEC,
+	SEG6_IPTUNNEL_SRH,
+	__SEG6_IPTUNNEL_MAX,
+};
+#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
+
+struct seg6_iptunnel_encap {
+	int flags;
+	struct ipv6_sr_hdr srh[0];
+};
+
+#define SEG6_IPTUN_ENCAP_SIZE(x) (sizeof(*(x)) + (((x)->srh->hdrlen + 1) << 3))
+
+#define SEG6_IPTUN_FLAG_ENCAP   0x1
+
+#endif
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index 669ecc9..dfe82ff 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -39,6 +39,8 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
 		return "MPLS";
 	case LWTUNNEL_ENCAP_ILA:
 		return "ILA";
+	case LWTUNNEL_ENCAP_SEG6:
+		return "SEG6";
 	case LWTUNNEL_ENCAP_IP6:
 	case LWTUNNEL_ENCAP_IP:
 	case LWTUNNEL_ENCAP_NONE:
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 931111f..192c59f 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -310,4 +310,13 @@ config IPV6_SEG6_CORE
 
 	  If unsure, say N.
 
+config IPV6_SEG6_IPTUNNEL
+	tristate "IPv6: Segment Routing IP Tunnels encapsulation support"
+	depends on IPV6_SEG6_CORE
+	---help---
+	  Support encapsulation and injection of SRH in locally emitted and
+	  forwarded packets.
+
+	  If unsure, say N.
+
 endif # IPV6
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 4254716..a040f90 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 obj-$(CONFIG_IPV6_FOU) += fou6.o
 obj-$(CONFIG_IPV6_SEG6_CORE) += seg6.o
+obj-$(CONFIG_IPV6_SEG6_IPTUNNEL) += seg6_iptunnel.o
 
 obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
 obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
new file mode 100644
index 0000000..ce7218a
--- /dev/null
+++ b/net/ipv6/seg6_iptunnel.c
@@ -0,0 +1,313 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/net.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/lwtunnel.h>
+#include <net/netevent.h>
+#include <net/netns/generic.h>
+#include <net/ip6_fib.h>
+#include <net/route.h>
+#include <net/seg6.h>
+#include <linux/seg6.h>
+#include <linux/seg6_iptunnel.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
+	[SEG6_IPTUNNEL_SRH]	= { .type = NLA_BINARY },
+};
+
+int nla_put_srh(struct sk_buff *skb, int attrtype,
+		struct seg6_iptunnel_encap *tuninfo)
+{
+	struct nlattr *nla;
+	struct seg6_iptunnel_encap *data;
+	int len;
+
+	len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
+
+	nla = nla_reserve(skb, attrtype, len);
+	if (!nla)
+		return -EMSGSIZE;
+
+	data = nla_data(nla);
+	memcpy(data, tuninfo, len);
+
+	return 0;
+}
+
+static void set_tun_src(struct net *net, struct net_device *dev,
+			struct in6_addr *daddr, struct in6_addr *saddr)
+{
+	struct in6_addr *tun_src;
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+
+	rcu_read_lock();
+
+	tun_src = rcu_dereference(sdata->tun_src);
+
+	if (!ipv6_addr_any(tun_src)) {
+		memcpy(saddr, tun_src, sizeof(struct in6_addr));
+	} else {
+		ipv6_dev_get_saddr(net, dev, daddr, IPV6_PREFER_SRC_PUBLIC,
+				   saddr);
+	}
+
+	rcu_read_unlock();
+}
+
+/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
+static int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
+{
+	struct ipv6hdr *hdr, *inner_hdr;
+	struct ipv6_sr_hdr *isrh;
+	struct net *net = dev_net(skb_dst(skb)->dev);
+	int hdrlen, tot_len, err;
+
+	hdrlen = (osrh->hdrlen + 1) << 3;
+	tot_len = hdrlen + sizeof(*hdr);
+
+	err = pskb_expand_head(skb, tot_len, 0, GFP_ATOMIC);
+	if (unlikely(err))
+		return err;
+
+	inner_hdr = ipv6_hdr(skb);
+
+	skb_push(skb, tot_len);
+	skb_reset_network_header(skb);
+	skb_mac_header_rebuild(skb);
+	hdr = ipv6_hdr(skb);
+
+	/* inherit tc, flowlabel and hlim
+	 * hlim will be decremented in ip6_forward() afterwards and
+	 * decapsulation will overwrite inner hlim with outer hlim
+	 */
+	ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
+		     ip6_flowlabel(inner_hdr));
+	hdr->hop_limit = inner_hdr->hop_limit;
+	hdr->nexthdr = NEXTHDR_ROUTING;
+
+	isrh = (void *)hdr + sizeof(*hdr);
+	memcpy(isrh, osrh, hdrlen);
+
+	isrh->nexthdr = NEXTHDR_IPV6;
+
+	hdr->daddr = isrh->segments[isrh->first_segment];
+	set_tun_src(net, skb->dev, &hdr->daddr, &hdr->saddr);
+
+	return 0;
+}
+
+/* insert an SRH within an IPv6 packet, just after the IPv6 header */
+static int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
+{
+	struct ipv6hdr *hdr, *oldhdr;
+	struct ipv6_sr_hdr *isrh;
+	int hdrlen, err;
+
+	hdrlen = (osrh->hdrlen + 1) << 3;
+
+	err = pskb_expand_head(skb, hdrlen, 0, GFP_ATOMIC);
+	if (unlikely(err))
+		return err;
+
+	oldhdr = ipv6_hdr(skb);
+
+	skb_push(skb, hdrlen);
+	skb_reset_network_header(skb);
+	skb_mac_header_rebuild(skb);
+
+	hdr = ipv6_hdr(skb);
+
+	memmove(hdr, oldhdr, sizeof(*hdr));
+
+	isrh = (void *)hdr + sizeof(*hdr);
+	memcpy(isrh, osrh, hdrlen);
+
+	isrh->nexthdr = hdr->nexthdr;
+	hdr->nexthdr = NEXTHDR_ROUTING;
+
+	isrh->segments[0] = hdr->daddr;
+	hdr->daddr = isrh->segments[isrh->first_segment];
+
+	return 0;
+}
+
+static int seg6_do_srh(struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb_dst(skb);
+	struct seg6_iptunnel_encap *tinfo = seg6_lwtunnel_encap(dst->lwtstate);
+	int err = 0;
+
+	if (likely(!skb->encapsulation)) {
+		skb_reset_inner_headers(skb);
+		skb->encapsulation = 1;
+	}
+
+	if (tinfo->flags & SEG6_IPTUN_FLAG_ENCAP) {
+		err = seg6_do_srh_encap(skb, tinfo->srh);
+	} else {
+		err = seg6_do_srh_inline(skb, tinfo->srh);
+		skb_reset_inner_headers(skb);
+	}
+
+	if (err)
+		return err;
+
+	ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+
+	skb_set_inner_protocol(skb, skb->protocol);
+
+	return 0;
+}
+
+int seg6_input(struct sk_buff *skb)
+{
+	int err;
+
+	err = seg6_do_srh(skb);
+	if (unlikely(err))
+		return err;
+
+	skb_dst_drop(skb);
+	ip6_route_input(skb);
+
+	return dst_input(skb);
+}
+
+int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+{
+	int err;
+	struct dst_entry *dst;
+	struct ipv6hdr *hdr;
+	struct flowi6 fl6;
+
+	err = seg6_do_srh(skb);
+	if (unlikely(err))
+		return err;
+
+	hdr = ipv6_hdr(skb);
+	fl6.daddr = hdr->daddr;
+	fl6.saddr = hdr->saddr;
+	fl6.flowlabel = ip6_flowinfo(hdr);
+	fl6.flowi6_mark = skb->mark;
+	fl6.flowi6_proto = hdr->nexthdr;
+
+	skb_dst_drop(skb);
+
+	err = ip6_dst_lookup(net, sk, &dst, &fl6);
+	if (unlikely(err))
+		return err;
+
+	skb_dst_set(skb, dst);
+
+	return dst_output(net, sk, skb);
+}
+
+static int seg6_build_state(struct net_device *dev, struct nlattr *nla,
+			    unsigned int family, const void *cfg,
+			    struct lwtunnel_state **ts)
+{
+	struct seg6_iptunnel_encap *tuninfo, *tuninfo_new;
+	struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
+	struct lwtunnel_state *newts;
+	int tuninfo_len;
+	int err;
+
+	err = nla_parse_nested(tb, SEG6_IPTUNNEL_MAX, nla,
+			       seg6_iptunnel_policy);
+
+	if (err < 0)
+		return err;
+
+	if (!tb[SEG6_IPTUNNEL_SRH])
+		return -EINVAL;
+
+	tuninfo = nla_data(tb[SEG6_IPTUNNEL_SRH]);
+	tuninfo_len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
+
+	newts = lwtunnel_state_alloc(tuninfo_len);
+	if (!newts)
+		return -ENOMEM;
+
+	newts->len = tuninfo_len;
+	tuninfo_new = seg6_lwtunnel_encap(newts);
+	memcpy(tuninfo_new, tuninfo, tuninfo_len);
+
+	newts->type = LWTUNNEL_ENCAP_SEG6;
+	newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
+			LWTUNNEL_STATE_INPUT_REDIRECT;
+
+	*ts = newts;
+
+	return 0;
+}
+
+static int seg6_fill_encap_info(struct sk_buff *skb,
+				struct lwtunnel_state *lwtstate)
+{
+	struct seg6_iptunnel_encap *tuninfo = seg6_lwtunnel_encap(lwtstate);
+
+	if (nla_put_srh(skb, SEG6_IPTUNNEL_SRH, tuninfo))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int seg6_encap_nlsize(struct lwtunnel_state *lwtstate)
+{
+	struct seg6_iptunnel_encap *tuninfo = seg6_lwtunnel_encap(lwtstate);
+
+	return nla_total_size(SEG6_IPTUN_ENCAP_SIZE(tuninfo));
+}
+
+static int seg6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
+{
+	struct seg6_iptunnel_encap *a_hdr = seg6_lwtunnel_encap(a);
+	struct seg6_iptunnel_encap *b_hdr = seg6_lwtunnel_encap(b);
+	int len = SEG6_IPTUN_ENCAP_SIZE(a_hdr);
+
+	if (len != SEG6_IPTUN_ENCAP_SIZE(b_hdr))
+		return 1;
+
+	return memcmp(a_hdr, b_hdr, len);
+}
+
+static const struct lwtunnel_encap_ops seg6_iptun_ops = {
+	.build_state = seg6_build_state,
+	.output = seg6_output,
+	.input = seg6_input,
+	.fill_encap = seg6_fill_encap_info,
+	.get_encap_size = seg6_encap_nlsize,
+	.cmp_encap = seg6_encap_cmp,
+};
+
+static int __init seg6_iptunnel_init(void)
+{
+	return lwtunnel_encap_add_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
+}
+module_init(seg6_iptunnel_init);
+
+static void __exit seg6_iptunnel_exit(void)
+{
+	lwtunnel_encap_del_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
+}
+module_exit(seg6_iptunnel_exit);
+
+MODULE_DESCRIPTION("Segment Routing with IPv6 IP Tunnels");
+MODULE_LICENSE("GPL v2");
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 5/9] ipv6: sr: add core files for SR HMAC support
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
                   ` (3 preceding siblings ...)
  2016-08-26 15:52 ` [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels David Lebrun
@ 2016-08-26 15:54 ` David Lebrun
  2016-08-26 15:54 ` [RFC 6/9] ipv6: sr: implement API to control SR HMAC structures David Lebrun
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:54 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

This patch adds the necessary functions to compute and check the HMAC signature
of an SR-enabled packet. Two HMAC algorithms are supported: hmac(sha1) and
hmac(sha256).

In order to avoid dynamic memory allocation for each HMAC computation,
a per-cpu ring buffer is allocated for this purpose.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 include/linux/seg6_hmac.h      |   6 +
 include/net/seg6_hmac.h        |  61 ++++++
 include/uapi/linux/seg6_hmac.h |  20 ++
 net/ipv6/seg6_hmac.c           | 432 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 519 insertions(+)
 create mode 100644 include/linux/seg6_hmac.h
 create mode 100644 include/net/seg6_hmac.h
 create mode 100644 include/uapi/linux/seg6_hmac.h
 create mode 100644 net/ipv6/seg6_hmac.c

diff --git a/include/linux/seg6_hmac.h b/include/linux/seg6_hmac.h
new file mode 100644
index 0000000..da437eb
--- /dev/null
+++ b/include/linux/seg6_hmac.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_SEG6_HMAC_H
+#define _LINUX_SEG6_HMAC_H
+
+#include <uapi/linux/seg6_hmac.h>
+
+#endif
diff --git a/include/net/seg6_hmac.h b/include/net/seg6_hmac.h
new file mode 100644
index 0000000..6e5ee6a
--- /dev/null
+++ b/include/net/seg6_hmac.h
@@ -0,0 +1,61 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_SEG6_HMAC_H
+#define _NET_SEG6_HMAC_H
+
+#include <net/flow.h>
+#include <net/ip6_fib.h>
+#include <net/sock.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/route.h>
+#include <net/seg6.h>
+#include <linux/seg6_hmac.h>
+
+#define SEG6_HMAC_MAX_DIGESTSIZE	160
+#define SEG6_HMAC_RING_SIZE		256
+
+struct seg6_hmac_info {
+	struct list_head list;
+
+	u32 hmackeyid;
+	char secret[SEG6_HMAC_SECRET_LEN];
+	u8 slen;
+	u8 alg_id;
+};
+
+struct seg6_hmac_algo {
+	u8 alg_id;
+	char name[64];
+	struct crypto_shash * __percpu *tfms;
+	struct shash_desc * __percpu *shashs;
+};
+
+extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo,
+			     struct ipv6_sr_hdr *hdr, struct in6_addr *saddr,
+			     u8 *output);
+extern struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key);
+extern int seg6_hmac_info_add(struct net *net, u32 key,
+			      struct seg6_hmac_info *hinfo);
+extern int seg6_hmac_info_del(struct net *net, u32 key,
+			      struct seg6_hmac_info *hinfo);
+extern int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
+			  struct ipv6_sr_hdr *srh);
+extern bool seg6_hmac_validate_skb(struct sk_buff *skb);
+extern int seg6_hmac_init(void);
+extern void seg6_hmac_exit(void);
+extern int seg6_hmac_net_init(struct net *net);
+extern void seg6_hmac_net_exit(struct net *net);
+
+#endif
diff --git a/include/uapi/linux/seg6_hmac.h b/include/uapi/linux/seg6_hmac.h
new file mode 100644
index 0000000..0b5eda7
--- /dev/null
+++ b/include/uapi/linux/seg6_hmac.h
@@ -0,0 +1,20 @@
+#ifndef _UAPI_LINUX_SEG6_HMAC_H
+#define _UAPI_LINUX_SEG6_HMAC_H
+
+#define SEG6_HMAC_SECRET_LEN	64
+#define SEG6_HMAC_FIELD_LEN	32
+
+struct sr6_tlv_hmac {
+	__u8 type;
+	__u8 len;
+	__u16 reserved;
+	__be32 hmackeyid;
+	__u8 hmac[SEG6_HMAC_FIELD_LEN];
+} __attribute__((packed));
+
+enum {
+	SEG6_HMAC_ALGO_SHA1 = 1,
+	SEG6_HMAC_ALGO_SHA256 = 2,
+};
+
+#endif
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
new file mode 100644
index 0000000..91bd59a
--- /dev/null
+++ b/net/ipv6/seg6_hmac.c
@@ -0,0 +1,432 @@
+/*
+ *  SR-IPv6 implementation -- HMAC functions
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <linux/mroute6.h>
+#include <linux/slab.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/xfrm.h>
+
+#include <linux/cryptohash.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <net/seg6.h>
+#include <net/genetlink.h>
+#include <net/seg6_hmac.h>
+#include <linux/random.h>
+
+static char * __percpu *hmac_ring;
+
+static struct seg6_hmac_algo hmac_algos[] = {
+	{
+		.alg_id = SEG6_HMAC_ALGO_SHA1,
+		.name = "hmac(sha1)",
+	},
+	{
+		.alg_id = SEG6_HMAC_ALGO_SHA256,
+		.name = "hmac(sha256)",
+	},
+};
+
+static struct seg6_hmac_algo *__hmac_get_algo(u8 alg_id)
+{
+	int i, alg_count;
+	struct seg6_hmac_algo *algo;
+
+	alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
+	for (i = 0; i < alg_count; i++) {
+		algo = &hmac_algos[i];
+		if (algo->alg_id == alg_id)
+			return algo;
+	}
+
+	return NULL;
+}
+
+static int __do_hmac(struct seg6_hmac_info *hinfo, const char *text, u8 psize,
+		     u8 *output, int outlen)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *shash;
+	struct seg6_hmac_algo *algo;
+	int ret, dgsize;
+
+	algo = __hmac_get_algo(hinfo->alg_id);
+	if (!algo)
+		return -ENOENT;
+
+	tfm = *this_cpu_ptr(algo->tfms);
+
+	dgsize = crypto_shash_digestsize(tfm);
+	if (dgsize > outlen) {
+		pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n",
+			 dgsize, outlen);
+		return -ENOMEM;
+	}
+
+	ret = crypto_shash_setkey(tfm, hinfo->secret, hinfo->slen);
+	if (ret < 0) {
+		pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret);
+		goto failed;
+	}
+
+	shash = *this_cpu_ptr(algo->shashs);
+	shash->tfm = tfm;
+
+	ret = crypto_shash_digest(shash, text, psize, output);
+	if (ret < 0) {
+		pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret);
+		goto failed;
+	}
+
+	return dgsize;
+
+failed:
+	return ret;
+}
+
+int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr,
+		      struct in6_addr *saddr, u8 *output)
+{
+	int plen, i, dgsize, wrsize;
+	char *ring, *off;
+	u8 tmp_out[SEG6_HMAC_MAX_DIGESTSIZE];
+	__be32 hmackeyid = cpu_to_be32(hinfo->hmackeyid);
+
+	/* a 160-byte buffer for digest output allows to store highest known
+	 * hash function (RadioGatun) with up to 1216 bits
+	 */
+
+	/* saddr(16) + first_seg(1) + cleanup(1) + keyid(4) + seglist(16n) */
+	plen = 16 + 1 + 1 + 4 + (hdr->first_segment + 1) * 16;
+
+	/* this limit allows for 14 segments */
+	if (plen >= SEG6_HMAC_RING_SIZE)
+		return -EMSGSIZE;
+
+	local_bh_disable();
+	ring = *this_cpu_ptr(hmac_ring);
+	off = ring;
+	memcpy(off, saddr, 16);
+	off += 16;
+	*off++ = hdr->first_segment;
+	*off++ = !!(sr_get_flags(hdr) & SR6_FLAG_CLEANUP) << 7;
+	memcpy(off, &hmackeyid, 4);
+	off += 4;
+
+	for (i = 0; i < hdr->first_segment + 1; i++) {
+		memcpy(off, hdr->segments + i, 16);
+		off += 16;
+	}
+
+	dgsize = __do_hmac(hinfo, ring, plen, tmp_out,
+			   SEG6_HMAC_MAX_DIGESTSIZE);
+	local_bh_enable();
+
+	if (dgsize < 0)
+		return dgsize;
+
+	wrsize = SEG6_HMAC_FIELD_LEN;
+	if (wrsize > dgsize)
+		wrsize = dgsize;
+
+	memset(output, 0, SEG6_HMAC_FIELD_LEN);
+	memcpy(output, tmp_out, wrsize);
+
+	return 0;
+}
+EXPORT_SYMBOL(seg6_hmac_compute);
+
+/* checks if an incoming SR-enabled packet's HMAC status matches
+ * the incoming policy.
+ *
+ * called with rcu_read_lock()
+ */
+bool seg6_hmac_validate_skb(struct sk_buff *skb)
+{
+	struct inet6_dev *idev;
+	struct ipv6_sr_hdr *srh;
+	struct sr6_tlv_hmac *tlv;
+	struct seg6_hmac_info *hinfo;
+	struct net *net = dev_net(skb->dev);
+	u8 hmac_output[SEG6_HMAC_FIELD_LEN];
+
+	idev = __in6_dev_get(skb->dev);
+
+	srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
+
+	tlv = seg6_get_tlv_hmac(srh);
+
+	/* mandatory check but no tlv */
+	if (idev->cnf.seg6_require_hmac > 0 && !tlv)
+		return false;
+
+	/* no check */
+	if (idev->cnf.seg6_require_hmac < 0)
+		return true;
+
+	/* check only if present */
+	if (idev->cnf.seg6_require_hmac == 0 && !tlv)
+		return true;
+
+	/* now, seg6_require_hmac >= 0 && tlv */
+
+	hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid));
+	if (!hinfo)
+		return false;
+
+	if (seg6_hmac_compute(hinfo, srh, &ipv6_hdr(skb)->saddr, hmac_output))
+		return false;
+
+	if (memcmp(hmac_output, tlv->hmac, SEG6_HMAC_FIELD_LEN) != 0)
+		return false;
+
+	return true;
+}
+
+/* called with rcu_read_lock() */
+struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key)
+{
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+	struct seg6_hmac_info *hinfo;
+
+	list_for_each_entry_rcu(hinfo, &sdata->hmac_infos, list) {
+		if (hinfo->hmackeyid == key)
+			return hinfo;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(seg6_hmac_info_lookup);
+
+int seg6_hmac_info_add(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
+{
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+	struct seg6_hmac_info *old_hinfo;
+
+	old_hinfo = seg6_hmac_info_lookup(net, key);
+	if (old_hinfo)
+		return -EEXIST;
+
+	list_add_rcu(&hinfo->list, &sdata->hmac_infos);
+
+	return 0;
+}
+EXPORT_SYMBOL(seg6_hmac_info_add);
+
+int seg6_hmac_info_del(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
+{
+	struct seg6_hmac_info *tmp;
+
+	tmp = seg6_hmac_info_lookup(net, key);
+	if (!tmp)
+		return -ENOENT;
+
+	/* entry was replaced, ignore deletion */
+	if (tmp != hinfo)
+		return -ENOENT;
+
+	list_del_rcu(&hinfo->list);
+	synchronize_net();
+
+	return 0;
+}
+EXPORT_SYMBOL(seg6_hmac_info_del);
+
+static void seg6_hmac_info_flush(struct net *net)
+{
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+	struct seg6_hmac_info *hinfo;
+
+	seg6_pernet_lock(net);
+	while ((hinfo = list_first_or_null_rcu(&sdata->hmac_infos,
+					       struct seg6_hmac_info,
+					       list)) != NULL) {
+		list_del_rcu(&hinfo->list);
+		seg6_pernet_unlock(net);
+		synchronize_net();
+		kfree(hinfo);
+		seg6_pernet_lock(net);
+	}
+
+	seg6_pernet_unlock(net);
+}
+
+int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
+		   struct ipv6_sr_hdr *srh)
+{
+	struct seg6_hmac_info *hinfo;
+	int err = -ENOENT;
+	struct sr6_tlv_hmac *tlv;
+
+	tlv = seg6_get_tlv(srh, SR6_TLV_HMAC);
+	if (!tlv)
+		return -EINVAL;
+
+	rcu_read_lock();
+
+	hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid));
+	if (!hinfo)
+		goto out;
+
+	memset(tlv->hmac, 0, SEG6_HMAC_FIELD_LEN);
+	err = seg6_hmac_compute(hinfo, srh, saddr, tlv->hmac);
+
+out:
+	rcu_read_unlock();
+	return err;
+}
+EXPORT_SYMBOL(seg6_push_hmac);
+
+static int seg6_hmac_init_ring(void)
+{
+	int i;
+
+	hmac_ring = alloc_percpu(char *);
+
+	if (!hmac_ring)
+		return -ENOMEM;
+
+	for_each_possible_cpu(i) {
+		char *ring = kzalloc(SEG6_HMAC_RING_SIZE, GFP_KERNEL);
+
+		if (!ring)
+			return -ENOMEM;
+
+		*per_cpu_ptr(hmac_ring, i) = ring;
+	}
+
+	return 0;
+}
+
+static int seg6_hmac_init_algo(void)
+{
+	int i, alg_count, cpu;
+	struct seg6_hmac_algo *algo;
+	struct crypto_shash *tfm;
+	struct shash_desc *shash;
+
+	alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
+
+	for (i = 0; i < alg_count; i++) {
+		int shsize;
+		struct crypto_shash **p_tfm;
+
+		algo = &hmac_algos[i];
+		algo->tfms = alloc_percpu(struct crypto_shash *);
+		if (!algo->tfms)
+			return -ENOMEM;
+
+		for_each_possible_cpu(cpu) {
+			tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL);
+			if (IS_ERR(tfm))
+				return PTR_ERR(tfm);
+			p_tfm = per_cpu_ptr(algo->tfms, cpu);
+			*p_tfm = tfm;
+		}
+
+		p_tfm = this_cpu_ptr(algo->tfms);
+		tfm = *p_tfm;
+
+		shsize = sizeof(*shash) + crypto_shash_descsize(tfm);
+
+		algo->shashs = alloc_percpu(struct shash_desc *);
+		if (!algo->shashs)
+			return -ENOMEM;
+
+		for_each_possible_cpu(cpu) {
+			shash = kzalloc(shsize, GFP_KERNEL);
+			if (!shash)
+				return -ENOMEM;
+			*per_cpu_ptr(algo->shashs, cpu) = shash;
+		}
+	}
+
+	return 0;
+}
+
+int __init seg6_hmac_init(void)
+{
+	int ret;
+
+	ret = seg6_hmac_init_ring();
+	if (ret < 0)
+		goto out;
+
+	ret = seg6_hmac_init_algo();
+
+out:
+	return ret;
+}
+
+int __net_init seg6_hmac_net_init(struct net *net)
+{
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+
+	INIT_LIST_HEAD(&sdata->hmac_infos);
+	return 0;
+}
+
+void __exit seg6_hmac_exit(void)
+{
+	int i, alg_count, cpu;
+	struct seg6_hmac_algo *algo = NULL;
+
+	for_each_possible_cpu(i) {
+		char *ring = *per_cpu_ptr(hmac_ring, i);
+
+		kfree(ring);
+	}
+	free_percpu(hmac_ring);
+
+	alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
+	for (i = 0; i < alg_count; i++) {
+		algo = &hmac_algos[i];
+		for_each_possible_cpu(cpu) {
+			struct crypto_shash *tfm;
+			struct shash_desc *shash;
+
+			shash = *per_cpu_ptr(algo->shashs, cpu);
+			kfree(shash);
+			tfm = *per_cpu_ptr(algo->tfms, cpu);
+			crypto_free_shash(tfm);
+		}
+		free_percpu(algo->tfms);
+		free_percpu(algo->shashs);
+	}
+}
+
+void __net_exit seg6_hmac_net_exit(struct net *net)
+{
+	seg6_hmac_info_flush(net);
+}
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 6/9] ipv6: sr: implement API to control SR HMAC structures
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
                   ` (4 preceding siblings ...)
  2016-08-26 15:54 ` [RFC 5/9] ipv6: sr: add core files for SR HMAC support David Lebrun
@ 2016-08-26 15:54 ` David Lebrun
  2016-08-26 15:54 ` [RFC 7/9] ipv6: sr: add calls to verify and insert HMAC signatures David Lebrun
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:54 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

This patch provides an implementation of the genetlink commands
to associate a given HMAC key identifier with an hashing algorithm
and a secret. It also provides a per-interface sysctl called
seg6_require_hmac, allowing a user-defined policy for processing
HMAC-signed SR-enabled packets. A value of -1 means that the HMAC
field will always be ignored. A value of 0 means that if an HMAC
field is present, its validity will be enforced (the packet is
dropped is the signature is incorrect). Finally, a value of 1 means
that any SR-enabled packet that does not contain an HMAC signature
or whose signature is incorrect will be dropped.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 include/linux/ipv6.h      |   3 +
 include/net/seg6.h        |  10 +++
 include/net/seg6_hmac.h   |   1 +
 include/uapi/linux/ipv6.h |   1 +
 net/ipv6/Kconfig          |   7 ++
 net/ipv6/Makefile         |   1 +
 net/ipv6/addrconf.c       |  18 +++++
 net/ipv6/seg6.c           | 179 ++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv6/seg6_hmac.c      |   2 +-
 9 files changed, 221 insertions(+), 1 deletion(-)

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index d3d8bd5..5a5998b 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -65,6 +65,9 @@ struct ipv6_devconf {
 	__s32		keep_addr_on_down;
 #ifdef CONFIG_IPV6_SEG6
 	__s32		seg6_enabled;
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	__s32		seg6_require_hmac;
+#endif
 #endif
 
 	struct ctl_table_header *sysctl_header;
diff --git a/include/net/seg6.h b/include/net/seg6.h
index af817f6..6d40e21 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -19,6 +19,9 @@
 #if IS_ENABLED(CONFIG_IPV6_SEG6_IPTUNNEL)
 #include <net/lwtunnel.h>
 #endif
+#ifdef CONFIG_IPV6_SEG6_HMAC
+#include <net/seg6_hmac.h>
+#endif
 
 #define SEG6_VERSION_MAJOR	0
 #define SEG6_VERSION_MINOR	30
@@ -26,6 +29,9 @@
 struct seg6_pernet_data {
 	spinlock_t lock;
 	struct in6_addr __rcu *tun_src;
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	struct list_head hmac_infos;
+#endif
 };
 
 static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
@@ -51,4 +57,8 @@ seg6_lwtunnel_encap(struct lwtunnel_state *lwtstate)
 }
 #endif
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+extern struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh);
+#endif
+
 #endif
diff --git a/include/net/seg6_hmac.h b/include/net/seg6_hmac.h
index 6e5ee6a..9646b7e 100644
--- a/include/net/seg6_hmac.h
+++ b/include/net/seg6_hmac.h
@@ -21,6 +21,7 @@
 #include <linux/ipv6.h>
 #include <linux/route.h>
 #include <net/seg6.h>
+#include <linux/seg6.h>
 #include <linux/seg6_hmac.h>
 
 #define SEG6_HMAC_MAX_DIGESTSIZE	160
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index a4addc8..b96c831 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -179,6 +179,7 @@ enum {
 	DEVCONF_DROP_UNSOLICITED_NA,
 	DEVCONF_KEEP_ADDR_ON_DOWN,
 	DEVCONF_SEG6_ENABLED,
+	DEVCONF_SEG6_REQUIRE_HMAC,
 	DEVCONF_MAX
 };
 
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 192c59f..94b3f04 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -319,4 +319,11 @@ config IPV6_SEG6_IPTUNNEL
 
 	  If unsure, say N.
 
+config IPV6_SEG6_HMAC
+	bool "IPv6: Segment Routing HMAC support"
+	depends on IPV6_SEG6_CORE=y
+	select CRYPTO_HMAC
+	select CRYPTO_SHA1
+	select CRYPTO_SHA256
+
 endif # IPV6
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index a040f90..2df6d18 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 obj-$(CONFIG_IPV6_FOU) += fou6.o
 obj-$(CONFIG_IPV6_SEG6_CORE) += seg6.o
 obj-$(CONFIG_IPV6_SEG6_IPTUNNEL) += seg6_iptunnel.o
+obj-$(CONFIG_IPV6_SEG6_HMAC) += seg6_hmac.o
 
 obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
 obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 9cc7dac..07f6f6b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -219,6 +219,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
 	.keep_addr_on_down	= 0,
 #ifdef CONFIG_IPV6_SEG6
 	.seg6_enabled		= 0,
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	.seg6_require_hmac	= 0,
+#endif
 #endif
 };
 
@@ -267,6 +270,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 	.keep_addr_on_down	= 0,
 #ifdef CONFIG_IPV6_SEG6
 	.seg6_enabled		= 0,
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	.seg6_require_hmac	= 0,
+#endif
 #endif
 };
 
@@ -4928,6 +4934,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 	array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
 #ifdef CONFIG_IPV6_SEG6
 	array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled;
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	array[DEVCONF_SEG6_REQUIRE_HMAC] = cnf->seg6_require_hmac;
+#endif
 #endif
 }
 
@@ -6026,6 +6035,15 @@ static const struct ctl_table addrconf_sysctl[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	{
+		.procname	= "seg6_require_hmac",
+		.data		= &ipv6_devconf.seg6_require_hmac,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+#endif
 #endif
 	{
 		/* sentinel */
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
index 5b8b4a1..bf6627f 100644
--- a/net/ipv6/seg6.c
+++ b/net/ipv6/seg6.c
@@ -25,6 +25,9 @@
 #include <net/genetlink.h>
 #include <linux/seg6.h>
 #include <linux/seg6_genl.h>
+#ifdef CONFIG_IPV6_SEG6_HMAC
+#include <net/seg6_hmac.h>
+#endif
 
 static struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
 	[SEG6_ATTR_DST]				= { .type = NLA_BINARY,
@@ -46,10 +49,103 @@ static struct genl_family seg6_genl_family = {
 	.netnsok = true,
 };
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh)
+{
+	struct sr6_tlv_hmac *tlv;
+
+	if (srh->hdrlen < (srh->first_segment + 1) * 2 + 5)
+		return NULL;
+
+	if (!(sr_get_flags(srh) & SR6_FLAG_HMAC))
+		return NULL;
+
+	tlv = (struct sr6_tlv_hmac *)
+	      ((char *)srh + ((srh->hdrlen + 1) << 3) - 40);
+
+	if (tlv->type != SR6_TLV_HMAC || tlv->len != 38)
+		return NULL;
+
+	return tlv;
+}
+#endif
+
+#ifdef CONFIG_IPV6_SEG6_HMAC
+static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = genl_info_net(info);
+	char *secret;
+	u32 hmackeyid;
+	u8 algid;
+	u8 slen;
+	struct seg6_hmac_info *hinfo;
+	int err = 0;
+
+	if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
+	    !info->attrs[SEG6_ATTR_SECRETLEN] ||
+	    !info->attrs[SEG6_ATTR_ALGID])
+		return -EINVAL;
+
+	hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
+	slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
+	algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
+
+	if (hmackeyid == 0)
+		return -EINVAL;
+
+	if (slen > SEG6_HMAC_SECRET_LEN)
+		return -EINVAL;
+
+	seg6_pernet_lock(net);
+	hinfo = seg6_hmac_info_lookup(net, hmackeyid);
+
+	if (!slen) {
+		if (!hinfo || seg6_hmac_info_del(net, hmackeyid, hinfo))
+			err = -ENOENT;
+		else
+			kfree(hinfo);
+
+		goto out_unlock;
+	}
+
+	if (!info->attrs[SEG6_ATTR_SECRET]) {
+		err = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (hinfo) {
+		if (seg6_hmac_info_del(net, hmackeyid, hinfo)) {
+			err = -ENOENT;
+			goto out_unlock;
+		}
+		kfree(hinfo);
+	}
+
+	secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
+
+	hinfo = kzalloc(sizeof(*hinfo), GFP_KERNEL);
+	if (!hinfo) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+
+	memcpy(hinfo->secret, secret, slen);
+	hinfo->slen = slen;
+	hinfo->alg_id = algid;
+	hinfo->hmackeyid = hmackeyid;
+
+	seg6_hmac_info_add(net, hmackeyid, hinfo);
+
+out_unlock:
+	seg6_pernet_unlock(net);
+	return err;
+}
+#else
 static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
 {
 	return -ENOTSUPP;
 }
+#endif
 
 static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
 {
@@ -113,10 +209,71 @@ free_msg:
 	return -ENOMEM;
 }
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
+				 struct sk_buff *msg)
+{
+	if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
+	    nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
+	    nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
+	    nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
+		return -1;
+
+	return 0;
+}
+
+static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
+					u32 portid, u32 seq, u32 flags,
+					struct sk_buff *skb, u8 cmd)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
+	if (!hdr)
+		return -ENOMEM;
+
+	if (__seg6_hmac_fill_info(hinfo, skb) < 0)
+		goto nla_put_failure;
+
+	genlmsg_end(skb, hdr);
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct net *net = sock_net(skb->sk);
+	struct seg6_pernet_data *sdata = seg6_pernet(net);
+	struct seg6_hmac_info *hinfo;
+	int idx = 0, ret;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(hinfo, &sdata->hmac_infos, list) {
+		if (idx++ < cb->args[0])
+			continue;
+
+		ret = __seg6_genl_dumphmac_element(hinfo,
+						   NETLINK_CB(cb->skb).portid,
+						   cb->nlh->nlmsg_seq,
+						   NLM_F_MULTI,
+						   skb, SEG6_CMD_DUMPHMAC);
+		if (ret)
+			break;
+	}
+	rcu_read_unlock();
+
+	cb->args[0] = idx;
+	return skb->len;
+}
+#else
 static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	return -ENOTSUPP;
 }
+#endif
 
 static struct genl_ops seg6_genl_ops[] = {
 	{
@@ -163,6 +320,10 @@ static int __net_init seg6_net_init(struct net *net)
 
 	net->ipv6.seg6_data = sdata;
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	seg6_hmac_net_init(net);
+#endif
+
 	return 0;
 }
 
@@ -170,6 +331,10 @@ static void __net_exit seg6_net_exit(struct net *net)
 {
 	struct seg6_pernet_data *sdata = seg6_pernet(net);
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	seg6_hmac_net_exit(net);
+#endif
+
 	kfree(sdata->tun_src);
 	kfree(sdata);
 }
@@ -191,10 +356,20 @@ static int __init seg6_init(void)
 	if (err)
 		goto out_unregister_genl;
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	err = seg6_hmac_init();
+	if (err)
+		goto out_unregister_pernet;
+#endif
+
 	pr_info("SR-IPv6: Release v%d.%d\n", SEG6_VERSION_MAJOR,
 		SEG6_VERSION_MINOR);
 out:
 	return err;
+#ifdef CONFIG_IPV6_SEG6_HMAC
+out_unregister_pernet:
+	unregister_pernet_subsys(&ip6_segments_ops);
+#endif
 out_unregister_genl:
 	genl_unregister_family(&seg6_genl_family);
 	goto out;
@@ -203,6 +378,10 @@ module_init(seg6_init);
 
 static void __exit seg6_exit(void)
 {
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	seg6_hmac_exit();
+#endif
+
 	unregister_pernet_subsys(&ip6_segments_ops);
 	genl_unregister_family(&seg6_genl_family);
 }
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index 91bd59a..99e90c8 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -289,7 +289,7 @@ int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
 	int err = -ENOENT;
 	struct sr6_tlv_hmac *tlv;
 
-	tlv = seg6_get_tlv(srh, SR6_TLV_HMAC);
+	tlv = seg6_get_tlv_hmac(srh);
 	if (!tlv)
 		return -EINVAL;
 
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 7/9] ipv6: sr: add calls to verify and insert HMAC signatures
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
                   ` (5 preceding siblings ...)
  2016-08-26 15:54 ` [RFC 6/9] ipv6: sr: implement API to control SR HMAC structures David Lebrun
@ 2016-08-26 15:54 ` David Lebrun
  2016-08-26 15:54 ` [RFC 8/9] ipv6: add source address argument for ipv6_push_nfrag_opts David Lebrun
  2016-08-26 15:54 ` [RFC 9/9] ipv6: sr: add support for SRH injection through setsockopt David Lebrun
  8 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:54 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

This patch enables the verification of the HMAC signature for transiting
SR-enabled packets, and its insertion on encapsulated/injected SRH.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 net/ipv6/exthdrs.c       | 10 ++++++++++
 net/ipv6/seg6_iptunnel.c | 17 +++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index e6f41fc..92b684a 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -49,6 +49,9 @@
 #endif
 #ifdef CONFIG_IPV6_SEG6
 #include <linux/seg6.h>
+#ifdef CONFIG_IPV6_SEG6_HMAC
+#include <net/seg6_hmac.h>
+#endif
 #endif
 
 #include <linux/uaccess.h>
@@ -313,6 +316,13 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
 		return -1;
 	}
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	if (!seg6_hmac_validate_skb(skb)) {
+		kfree_skb(skb);
+		return -1;
+	}
+#endif
+
 looped_back:
 	last_addr = hdr->segments;
 
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index ce7218a..f115cc5 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -109,6 +109,14 @@ static int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
 	hdr->daddr = isrh->segments[isrh->first_segment];
 	set_tun_src(net, skb->dev, &hdr->daddr, &hdr->saddr);
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	if (sr_get_flags(isrh) & SR6_FLAG_HMAC) {
+		err = seg6_push_hmac(net, &hdr->saddr, isrh);
+		if (unlikely(err))
+			return err;
+	}
+#endif
+
 	return 0;
 }
 
@@ -118,6 +126,7 @@ static int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
 	struct ipv6hdr *hdr, *oldhdr;
 	struct ipv6_sr_hdr *isrh;
 	int hdrlen, err;
+	struct net *net = dev_net(skb_dst(skb)->dev);
 
 	hdrlen = (osrh->hdrlen + 1) << 3;
 
@@ -144,6 +153,14 @@ static int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
 	isrh->segments[0] = hdr->daddr;
 	hdr->daddr = isrh->segments[isrh->first_segment];
 
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	if (sr_get_flags(isrh) & SR6_FLAG_HMAC) {
+		err = seg6_push_hmac(net, &hdr->saddr, isrh);
+		if (unlikely(err))
+			return err;
+	}
+#endif
+
 	return 0;
 }
 
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 8/9] ipv6: add source address argument for ipv6_push_nfrag_opts
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
                   ` (6 preceding siblings ...)
  2016-08-26 15:54 ` [RFC 7/9] ipv6: sr: add calls to verify and insert HMAC signatures David Lebrun
@ 2016-08-26 15:54 ` David Lebrun
  2016-08-26 15:54 ` [RFC 9/9] ipv6: sr: add support for SRH injection through setsockopt David Lebrun
  8 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:54 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

This patch prepares for insertion of SRH through setsockopt().
The new source address argument is used when an HMAC field is
present in the SRH, which must be filled. The HMAC signature
process requires the source address as input text.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 include/net/ipv6.h    | 3 ++-
 net/ipv6/exthdrs.c    | 6 +++---
 net/ipv6/ip6_output.c | 5 +++--
 net/ipv6/ip6_tunnel.c | 2 +-
 4 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 8fed1cd..0a3622b 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -932,7 +932,8 @@ int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
  */
 
 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
-			  u8 *proto, struct in6_addr **daddr_p);
+			  u8 *proto, struct in6_addr **daddr_p,
+			  struct in6_addr *saddr);
 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
 			 u8 *proto);
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 92b684a..ff469b5 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -833,7 +833,7 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
 
 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
 			    struct ipv6_rt_hdr *opt,
-			    struct in6_addr **addr_p)
+			    struct in6_addr **addr_p, struct in6_addr *saddr)
 {
 	struct rt0_hdr *phdr, *ihdr;
 	int hops;
@@ -867,10 +867,10 @@ static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv
 
 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
 			  u8 *proto,
-			  struct in6_addr **daddr)
+			  struct in6_addr **daddr, struct in6_addr *saddr)
 {
 	if (opt->srcrt) {
-		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
+		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr, saddr);
 		/*
 		 * IPV6_RTHDRDSTOPTS is ignored
 		 * unless IPV6_RTHDR is set (RFC3542).
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 1dfc402..8cd620b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -195,7 +195,8 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
 		if (opt->opt_flen)
 			ipv6_push_frag_opts(skb, opt, &proto);
 		if (opt->opt_nflen)
-			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
+			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
+					     &fl6->saddr);
 	}
 
 	skb_push(skb, sizeof(struct ipv6hdr));
@@ -1665,7 +1666,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
 	if (opt && opt->opt_flen)
 		ipv6_push_frag_opts(skb, opt, &proto);
 	if (opt && opt->opt_nflen)
-		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
+		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst, &fl6->saddr);
 
 	skb_push(skb, sizeof(struct ipv6hdr));
 	skb_reset_network_header(skb);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 2050217..c02fd95 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1117,7 +1117,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
 
 	if (encap_limit >= 0) {
 		init_tel_txopt(&opt, encap_limit);
-		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
+		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL, NULL);
 	}
 
 	/* Calculate max headroom for all the headers and adjust
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC 9/9] ipv6: sr: add support for SRH injection through setsockopt
  2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
                   ` (7 preceding siblings ...)
  2016-08-26 15:54 ` [RFC 8/9] ipv6: add source address argument for ipv6_push_nfrag_opts David Lebrun
@ 2016-08-26 15:54 ` David Lebrun
  8 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-08-26 15:54 UTC (permalink / raw)
  To: netdev; +Cc: David Lebrun

This patch adds support for per-socket SRH injection with the setsockopt
system call through the IPPROTO_IPV6, IPV6_RTHDR options.
The SRH is pushed through the ipv6_push_nfrag_opts function.

Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
---
 net/ipv6/Kconfig         |  5 ++--
 net/ipv6/exthdrs.c       | 69 +++++++++++++++++++++++++++++++++++++++++++++---
 net/ipv6/ipv6_sockglue.c |  4 +++
 3 files changed, 72 insertions(+), 6 deletions(-)

diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 94b3f04..85edee2 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -305,8 +305,9 @@ config IPV6_SEG6_CORE
 	depends on IPV6_SEG6
 	---help---
 	  Enable the core functionalities required for a control plane support
-	  of SR-IPv6. This option is not useful by itself, it rather provides
-	  the code base for a control plane support.
+	  of SR-IPv6. It also enables the support for per-socket SRH injection
+	  through the setsockopt() system call with the IPPROTO_IPV6,IPV6_RTHDR
+	  options.
 
 	  If unsure, say N.
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index ff469b5..c1cc80c 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -831,9 +831,9 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
  *	for headers.
  */
 
-static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
-			    struct ipv6_rt_hdr *opt,
-			    struct in6_addr **addr_p, struct in6_addr *saddr)
+static void ipv6_push_rthdr0(struct sk_buff *skb, u8 *proto,
+			     struct ipv6_rt_hdr *opt,
+			     struct in6_addr **addr_p, struct in6_addr *saddr)
 {
 	struct rt0_hdr *phdr, *ihdr;
 	int hops;
@@ -856,6 +856,57 @@ static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
 	*proto = NEXTHDR_ROUTING;
 }
 
+#if IS_ENABLED(CONFIG_IPV6_SEG6_CORE)
+static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
+			     struct ipv6_rt_hdr *opt,
+			     struct in6_addr **addr_p, struct in6_addr *saddr)
+{
+	struct ipv6_sr_hdr *sr_phdr, *sr_ihdr;
+	struct net *net = NULL;
+	int plen, hops;
+
+	if (skb->dev)
+		net = dev_net(skb->dev);
+	else if (skb->sk)
+		net = sock_net(skb->sk);
+
+	WARN_ON(!net);
+
+	sr_ihdr = (struct ipv6_sr_hdr *)opt;
+	plen = (sr_ihdr->hdrlen + 1) << 3;
+
+	sr_phdr = (struct ipv6_sr_hdr *)skb_push(skb, plen);
+	memcpy(sr_phdr, sr_ihdr, sizeof(struct ipv6_sr_hdr));
+
+	hops = sr_ihdr->first_segment + 1;
+	memcpy(sr_phdr->segments + 1, sr_ihdr->segments + 1,
+	       (hops - 1) * sizeof(struct in6_addr));
+
+	sr_phdr->segments[0] = **addr_p;
+	*addr_p = &sr_ihdr->segments[hops - 1];
+
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	if (net && (sr_get_flags(sr_phdr) & SR6_FLAG_HMAC))
+		seg6_push_hmac(net, saddr, sr_phdr);
+#endif
+
+	sr_phdr->nexthdr = *proto;
+	*proto = NEXTHDR_ROUTING;
+}
+#endif
+
+static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
+			    struct ipv6_rt_hdr *opt,
+			    struct in6_addr **addr_p, struct in6_addr *saddr)
+{
+#if IS_ENABLED(CONFIG_IPV6_SEG6_CORE)
+	if (opt->type == IPV6_SRCRT_TYPE_4)
+		ipv6_push_rthdr4(skb, proto, opt, addr_p, saddr);
+#endif
+	if (opt->type == IPV6_SRCRT_TYPE_0)
+		ipv6_push_rthdr0(skb, proto, opt, addr_p, saddr);
+}
+
 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
 {
 	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
@@ -1097,7 +1148,17 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
 		return NULL;
 
 	*orig = fl6->daddr;
-	fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
+
+#if IS_ENABLED(CONFIG_IPV6_SEG6_CORE)
+	if (opt->srcrt->type == IPV6_SRCRT_TYPE_4) {
+		struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *)opt->srcrt;
+
+		fl6->daddr = srh->segments[srh->first_segment];
+	}
+#endif
+	if (opt->srcrt->type == IPV6_SRCRT_TYPE_0)
+		fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
+
 	return orig;
 }
 EXPORT_SYMBOL_GPL(fl6_update_dst);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 5330262..069b169 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -429,6 +429,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 
 				break;
 #endif
+#if IS_ENABLED(CONFIG_IPV6_SEG6_CORE)
+			case IPV6_SRCRT_TYPE_4:
+				break;
+#endif
 			default:
 				goto sticky_done;
 			}
-- 
2.3.6

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels
  2016-08-26 15:52 ` [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels David Lebrun
@ 2016-08-29 14:52   ` Roopa Prabhu
  2016-09-01 13:32     ` David Lebrun
  0 siblings, 1 reply; 26+ messages in thread
From: Roopa Prabhu @ 2016-08-29 14:52 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

On 8/26/16, 8:52 AM, David Lebrun wrote:
> 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 via <gw> encap seg6 mode encap segs fc42::1,fc42::2,fc42::3
>
> 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.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---

You will need to account for lwtunnel headroom ?
https://patchwork.ozlabs.org/patch/662632/

thanks,
Roopa

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
@ 2016-08-29 15:31   ` Roopa Prabhu
  2016-08-31 14:57     ` Nicolas Dichtel
  2016-09-01 13:21     ` David Lebrun
  2016-08-31 14:59   ` Nicolas Dichtel
                     ` (3 subsequent siblings)
  4 siblings, 2 replies; 26+ messages in thread
From: Roopa Prabhu @ 2016-08-29 15:31 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

On 8/26/16, 8:52 AM, David Lebrun wrote:
> This patch adds the necessary hooks and structures to provide support
> for SR-IPv6 control plane, essentially the Generic Netlink commands
> that will be used for userspace control over the Segment Routing
> kernel structures.
>
> The genetlink commands provide control over two different structures:
> tunnel source and HMAC data. The tunnel source is the source address
> that will be used by default when encapsulating packets into an
> outer IPv6 header + SRH. If the tunnel source is set to :: then an
> address of the outgoing interface will be selected as the source.
>
> The HMAC commands currently just return ENOTSUPP and will be implemented
> in a future patch.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
>
This looks fine. But, i am just trying to see if this can be rtnetlink.
Have you considered it already ?.
We would like to keep the API consistent or abstracted to accommodate SR-MPLS in the
future too. so, any abstraction there will help.

what is your control-plane software using this ?
quagga or any-other routing daemon ?

Thanks,
Roopa

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
  2016-08-26 15:52 ` [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header) David Lebrun
@ 2016-08-31 14:51   ` Nicolas Dichtel
  2016-09-01 13:11     ` David Lebrun
  2016-08-31 17:13   ` Stephen Hemminger
  1 sibling, 1 reply; 26+ messages in thread
From: Nicolas Dichtel @ 2016-08-31 14:51 UTC (permalink / raw)
  To: David Lebrun, netdev

Le 26/08/2016 à 17:52, David Lebrun a écrit :
> Implement minimal support for processing of SR-enabled packets
> as described in
> https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-01.
> 
> This patch implements the following operations:
> - Intermediate segment endpoint: incrementation of active segment and rerouting.
> - Egress for SR-encapsulated packets: decapsulation of outer IPv6 header + SRH
>   and routing of inner packet.
> - Cleanup flag support for SR-inlined packets: removal of SRH if we are the
>   penultimate segment endpoint.
> 
> A per-interface sysctl seg6_enabled is provided, to accept/deny SR-enabled
> packets. Default is deny.
> 
> This patch does not provide support for HMAC-signed packets.
> 
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
Thanks for proposing this feature. It would be great to have it upstream.

[snip]
> +config IPV6_SEG6
> +	bool "IPv6: Segment Routing support"
> +	depends on IPV6
> +	---help---
> +	  Experimental support for IPv6 Segment Routing dataplane as defined
> +	  in IETF draft-ietf-6man-segment-routing-header-01. This option
> +	  enables the processing of SR-enabled packets allowing the kernel
> +	  to act as a segment endpoint (intermediate or egress).
> +
> +	  If unsure, say N.
> +
I don't think that the option is needed. At the end, every distributions will
turn it on.

[snip]
> +#ifdef CONFIG_IPV6_SEG6
> +	{
> +		.procname	= "seg6_enabled",
> +		.data		= &ipv6_devconf.seg6_enabled,
> +		.maxlen		= sizeof(int),
> +		.mode		= 0644,
> +		.proc_handler	= proc_dointvec,
> +	},
> +#endif
Don't forget to document this option in Documentation/networking/ip-sysctl.txt.
Don't forget to explain how 'all' works ;-)
It would be nice to also add it in netconf subsystem (see 'git grep netconf
net/ipv6').

[snip]
> +#ifdef CONFIG_IPV6_SEG6
> +static int ipv6_srh_rcv(struct sk_buff *skb)
> +{
> +	struct inet6_skb_parm *opt = IP6CB(skb);
> +	struct in6_addr *addr = NULL, *last_addr = NULL, *active_addr = NULL;
> +	struct ipv6_sr_hdr *hdr;
> +	struct net *net = dev_net(skb->dev);
> +	int cleanup = 0;
> +	struct inet6_dev *idev;
> +	int accept_seg6;
nit: better to follow the 'reverse christmas tree' scheme when declaring variables.

> +
> +	hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +	idev = __in6_dev_get(skb->dev);
> +
> +	accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
> +	if (accept_seg6 > idev->cnf.seg6_enabled)
> +		accept_seg6 = idev->cnf.seg6_enabled;
> +
> +	if (!accept_seg6) {
> +		kfree_skb(skb);
> +		return -1;
> +	}
> +
> +looped_back:
> +	last_addr = hdr->segments;
> +
> +	if (hdr->segments_left > 0) {
> +		if (hdr->nexthdr != NEXTHDR_IPV6 && hdr->segments_left == 1 &&
> +		    sr_get_flags(hdr) & SR6_FLAG_CLEANUP)
> +			cleanup = 1;
> +	} else {
> +		if (hdr->nexthdr == NEXTHDR_IPV6) {
> +			int offset = (hdr->hdrlen + 1) << 3;
> +
> +			if (!pskb_pull(skb, offset)) {
> +				kfree_skb(skb);
> +				return -1;
> +			}
> +			skb_postpull_rcsum(skb, skb_transport_header(skb),
> +					   offset);
> +
> +			skb_reset_network_header(skb);
> +			skb_reset_transport_header(skb);
> +			skb->encapsulation = 0;
> +
> +			__skb_tunnel_rx(skb, skb->dev, net);
> +
> +			netif_rx(skb);
> +			return -1;
> +		}
> +
> +		opt->srcrt = skb_network_header_len(skb);
> +		opt->lastopt = opt->srcrt;
> +		skb->transport_header += (hdr->hdrlen + 1) << 3;
> +		opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
> +
> +		return 1;
> +	}
> +
> +	if (skb_cloned(skb)) {
> +		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
> +			__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
> +					IPSTATS_MIB_OUTDISCARDS);
> +			kfree_skb(skb);
> +			return -1;
> +		}
> +	}
> +
> +	if (skb->ip_summed == CHECKSUM_COMPLETE)
> +		skb->ip_summed = CHECKSUM_NONE;
> +
> +	hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +	active_addr = hdr->segments + hdr->segments_left;
> +	hdr->segments_left--;
> +	addr = hdr->segments + hdr->segments_left;
> +
> +	ipv6_hdr(skb)->daddr = *addr;
> +
> +	skb_push(skb, sizeof(struct ipv6hdr));
> +
> +	/* cleanup */
> +
> +	if (cleanup) {
> +		int srhlen = (hdr->hdrlen + 1) << 3;
> +		int nh = hdr->nexthdr;
> +
> +		memmove(skb_network_header(skb) + srhlen,
> +			skb_network_header(skb),
> +			(unsigned char *)hdr - skb_network_header(skb));
> +		skb_pull(skb, srhlen);
> +		skb->network_header += srhlen;
> +		ipv6_hdr(skb)->nexthdr = nh;
> +		ipv6_hdr(skb)->payload_len = htons(skb->len -
> +						   sizeof(struct ipv6hdr));
> +	}
> +
> +	skb_dst_drop(skb);
> +
> +	ip6_route_input(skb);
The destination address has now changed and the packet is routed again.
skb->nfct is not updated, it is intentional? I'm asking me if it's conceptually
right.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-29 15:31   ` Roopa Prabhu
@ 2016-08-31 14:57     ` Nicolas Dichtel
  2016-09-01 13:21     ` David Lebrun
  1 sibling, 0 replies; 26+ messages in thread
From: Nicolas Dichtel @ 2016-08-31 14:57 UTC (permalink / raw)
  To: Roopa Prabhu, David Lebrun; +Cc: netdev

Le 29/08/2016 à 17:31, Roopa Prabhu a écrit :
> On 8/26/16, 8:52 AM, David Lebrun wrote:
>> This patch adds the necessary hooks and structures to provide support
>> for SR-IPv6 control plane, essentially the Generic Netlink commands
>> that will be used for userspace control over the Segment Routing
>> kernel structures.
>>
>> The genetlink commands provide control over two different structures:
>> tunnel source and HMAC data. The tunnel source is the source address
>> that will be used by default when encapsulating packets into an
>> outer IPv6 header + SRH. If the tunnel source is set to :: then an
>> address of the outgoing interface will be selected as the source.
>>
>> The HMAC commands currently just return ENOTSUPP and will be implemented
>> in a future patch.
>>
>> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
>>
> This looks fine. But, i am just trying to see if this can be rtnetlink.
I agree with Roopa, why not using rtnl?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
  2016-08-29 15:31   ` Roopa Prabhu
@ 2016-08-31 14:59   ` Nicolas Dichtel
  2016-08-31 17:10   ` Stephen Hemminger
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 26+ messages in thread
From: Nicolas Dichtel @ 2016-08-31 14:59 UTC (permalink / raw)
  To: David Lebrun, netdev

Le 26/08/2016 à 17:52, David Lebrun a écrit :
[snip]
> +#define SEG6_VERSION_MAJOR	0
> +#define SEG6_VERSION_MINOR	30
nit: This kind of macros are not used anymore upstream. The git sha1 or the
linux version perfectly identifies the version.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
  2016-08-29 15:31   ` Roopa Prabhu
  2016-08-31 14:59   ` Nicolas Dichtel
@ 2016-08-31 17:10   ` Stephen Hemminger
  2016-09-01 13:25     ` David Lebrun
  2016-08-31 17:11   ` Stephen Hemminger
  2016-08-31 17:11   ` Stephen Hemminger
  4 siblings, 1 reply; 26+ messages in thread
From: Stephen Hemminger @ 2016-08-31 17:10 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

On Fri, 26 Aug 2016 17:52:40 +0200
David Lebrun <david.lebrun@uclouvain.be> wrote:

> +
> +static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
> +{
> +	return net->ipv6.seg6_data;
> +}
> +
> +static inline void seg6_pernet_lock(struct net *net)
> +{
> +	spin_lock(&seg6_pernet(net)->lock);
> +}
> +
> +static inline void seg6_pernet_unlock(struct net *net)
> +{
> +	spin_unlock(&seg6_pernet(net)->lock);
> +}

Since these are for control operations why a mutex?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
                     ` (2 preceding siblings ...)
  2016-08-31 17:10   ` Stephen Hemminger
@ 2016-08-31 17:11   ` Stephen Hemminger
  2016-08-31 17:11   ` Stephen Hemminger
  4 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2016-08-31 17:11 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

On Fri, 26 Aug 2016 17:52:40 +0200
David Lebrun <david.lebrun@uclouvain.be> wrote:

> +static struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
> +	[SEG6_ATTR_DST]				= { .type = NLA_BINARY,
> +		.len = sizeof(struct in6_addr) },
> +	[SEG6_ATTR_DSTLEN]			= { .type = NLA_S32, },
> +	[SEG6_ATTR_HMACKEYID]		= { .type = NLA_U32, },
> +	[SEG6_ATTR_SECRET]			= { .type = NLA_BINARY, },
> +	[SEG6_ATTR_SECRETLEN]		= { .type = NLA_U8, },
> +	[SEG6_ATTR_ALGID]			= { .type = NLA_U8, },
> +	[SEG6_ATTR_HMACINFO]		= { .type = NLA_NESTED, },
> +};

Should be const?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
                     ` (3 preceding siblings ...)
  2016-08-31 17:11   ` Stephen Hemminger
@ 2016-08-31 17:11   ` Stephen Hemminger
  4 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2016-08-31 17:11 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

On Fri, 26 Aug 2016 17:52:40 +0200
David Lebrun <david.lebrun@uclouvain.be> wrote:

> +static struct genl_ops seg6_genl_ops[] = {
> +	{
> +		.cmd	= SEG6_CMD_SETHMAC,
> +		.doit	= seg6_genl_sethmac,
> +		.policy	= seg6_genl_policy,
> +		.flags	= GENL_ADMIN_PERM,
> +	},
> +	{
> +		.cmd	= SEG6_CMD_DUMPHMAC,
> +		.dumpit	= seg6_genl_dumphmac,
> +		.policy	= seg6_genl_policy,
> +		.flags	= GENL_ADMIN_PERM,
> +	},
> +	{
> +		.cmd	= SEG6_CMD_SET_TUNSRC,
> +		.doit	= seg6_genl_set_tunsrc,
> +		.policy	= seg6_genl_policy,
> +		.flags	= GENL_ADMIN_PERM,
> +	},
> +	{
> +		.cmd	= SEG6_CMD_GET_TUNSRC,
> +		.doit	= seg6_genl_get_tunsrc,
> +		.policy = seg6_genl_policy,
> +		.flags	= GENL_ADMIN_PERM,
> +	},
> +};
> +

Should also be const

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
  2016-08-26 15:52 ` [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header) David Lebrun
  2016-08-31 14:51   ` Nicolas Dichtel
@ 2016-08-31 17:13   ` Stephen Hemminger
  1 sibling, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2016-08-31 17:13 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

On Fri, 26 Aug 2016 17:52:39 +0200
David Lebrun <david.lebrun@uclouvain.be> wrote:

> +
> +	/* cleanup */
> +
> +	if (cleanup) {

Unnecessary comment, you aren't saying anything with this.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
  2016-08-31 14:51   ` Nicolas Dichtel
@ 2016-09-01 13:11     ` David Lebrun
  2016-09-01 13:58       ` Nicolas Dichtel
  0 siblings, 1 reply; 26+ messages in thread
From: David Lebrun @ 2016-09-01 13:11 UTC (permalink / raw)
  To: nicolas.dichtel, netdev

[-- Attachment #1: Type: text/plain, Size: 2193 bytes --]

On 08/31/2016 04:51 PM, Nicolas Dichtel wrote:
> Thanks for proposing this feature. It would be great to have it upstream.
> 

Thanks for the feedback :)

> [snip]
>> +config IPV6_SEG6
>> +	bool "IPv6: Segment Routing support"
>> +	depends on IPV6
>> +	---help---
>> +	  Experimental support for IPv6 Segment Routing dataplane as defined
>> +	  in IETF draft-ietf-6man-segment-routing-header-01. This option
>> +	  enables the processing of SR-enabled packets allowing the kernel
>> +	  to act as a segment endpoint (intermediate or egress).
>> +
>> +	  If unsure, say N.
>> +
> I don't think that the option is needed. At the end, every distributions will
> turn it on.
> 

Are you sure ? This is a rather specific feature, used in specific
environments. Not that I would mind removing the option if it makes sense.

> [snip]
>> +#ifdef CONFIG_IPV6_SEG6
>> +	{
>> +		.procname	= "seg6_enabled",
>> +		.data		= &ipv6_devconf.seg6_enabled,
>> +		.maxlen		= sizeof(int),
>> +		.mode		= 0644,
>> +		.proc_handler	= proc_dointvec,
>> +	},
>> +#endif
> Don't forget to document this option in Documentation/networking/ip-sysctl.txt.
> Don't forget to explain how 'all' works ;-)
> It would be nice to also add it in netconf subsystem (see 'git grep netconf
> net/ipv6').
> 

Right ! I didn't think of that doc file. Noted for netconf.

> [snip]
>> +#ifdef CONFIG_IPV6_SEG6
>> +static int ipv6_srh_rcv(struct sk_buff *skb)
>> +{
>> +	struct inet6_skb_parm *opt = IP6CB(skb);
>> +	struct in6_addr *addr = NULL, *last_addr = NULL, *active_addr = NULL;
>> +	struct ipv6_sr_hdr *hdr;
>> +	struct net *net = dev_net(skb->dev);
>> +	int cleanup = 0;
>> +	struct inet6_dev *idev;
>> +	int accept_seg6;
> nit: better to follow the 'reverse christmas tree' scheme when declaring variables.
> 

Noted


>> +
>> +	ip6_route_input(skb);
> The destination address has now changed and the packet is routed again.
> skb->nfct is not updated, it is intentional? I'm asking me if it's conceptually
> right.
> 

I fail to see any usecase where conntrack would run on SR-enabled
packets. Things such as NAT would just defeat the purpose.

David


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-29 15:31   ` Roopa Prabhu
  2016-08-31 14:57     ` Nicolas Dichtel
@ 2016-09-01 13:21     ` David Lebrun
  2016-09-05 10:05       ` Nicolas Dichtel
  1 sibling, 1 reply; 26+ messages in thread
From: David Lebrun @ 2016-09-01 13:21 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 1157 bytes --]

On 08/29/2016 05:31 PM, Roopa Prabhu wrote:
> This looks fine. But, i am just trying to see if this can be rtnetlink.
> Have you considered it already ?.
> We would like to keep the API consistent or abstracted to accommodate SR-MPLS in the
> future too. so, any abstraction there will help.
> 
> what is your control-plane software using this ?
> quagga or any-other routing daemon ?
> 
> Thanks,
> Roopa
> 

rtnetlink is used for the routing part through the lwtunnels. In this
specific patch, the API is intended to configure namespace-wide
parameters such as a map of hmackeyid -> hashfn,secret, without
connection to particular routes. I agree that the tunsrc parameter could
be provided through rtnetlink, but the hmac data cannot (which by the
way does not exist for SR-MPLS).

The "control plane software" that currently uses that is simply a
patched version of iproute2 with SR support (which I will submit when
this patch series is hopefully merged). (e.g. ip sr set hmac blahblah)

More advanced control plane softwares are currently under development
and will be presented in upcoming academic publications.

David


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-08-31 17:10   ` Stephen Hemminger
@ 2016-09-01 13:25     ` David Lebrun
  2016-09-01 17:15       ` Stephen Hemminger
  0 siblings, 1 reply; 26+ messages in thread
From: David Lebrun @ 2016-09-01 13:25 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 269 bytes --]

On 08/31/2016 07:10 PM, Stephen Hemminger wrote:
> Since these are for control operations why a mutex?

I am not sure to understand the question. The spinlock is used on the
RCU write side of the namespace-wide parameters to prevent concurrent
writes.

David


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels
  2016-08-29 14:52   ` Roopa Prabhu
@ 2016-09-01 13:32     ` David Lebrun
  0 siblings, 0 replies; 26+ messages in thread
From: David Lebrun @ 2016-09-01 13:32 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 196 bytes --]

On 08/29/2016 04:52 PM, Roopa Prabhu wrote:
> You will need to account for lwtunnel headroom ?
> https://patchwork.ozlabs.org/patch/662632/
> 
> thanks,
> Roopa

Indeed, thanks

David


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
  2016-09-01 13:11     ` David Lebrun
@ 2016-09-01 13:58       ` Nicolas Dichtel
  0 siblings, 0 replies; 26+ messages in thread
From: Nicolas Dichtel @ 2016-09-01 13:58 UTC (permalink / raw)
  To: David Lebrun, netdev, netfilter-devel

Le 01/09/2016 à 15:11, David Lebrun a écrit :
> On 08/31/2016 04:51 PM, Nicolas Dichtel wrote:
[snip]
>>> +config IPV6_SEG6
>>> +	bool "IPv6: Segment Routing support"
>>> +	depends on IPV6
>>> +	---help---
>>> +	  Experimental support for IPv6 Segment Routing dataplane as defined
>>> +	  in IETF draft-ietf-6man-segment-routing-header-01. This option
>>> +	  enables the processing of SR-enabled packets allowing the kernel
>>> +	  to act as a segment endpoint (intermediate or egress).
>>> +
>>> +	  If unsure, say N.
>>> +
>> I don't think that the option is needed. At the end, every distributions will
>> turn it on.
>>
> 
> Are you sure ? This is a rather specific feature, used in specific
> environments. Not that I would mind removing the option if it makes sense.
Check default config file of a standard distributions (ubuntu, debian, ...), all
options are enabled (MIP6, SIT_6RD, PIMSM_v2, etc. ;-)).
Anyway, one option is enough. You add 3 or 4 options in your series.

[snip]

>>> +
>>> +	ip6_route_input(skb);
>> The destination address has now changed and the packet is routed again.
>> skb->nfct is not updated, it is intentional? I'm asking me if it's conceptually
>> right.
>>
> 
> I fail to see any usecase where conntrack would run on SR-enabled
> packets. Things such as NAT would just defeat the purpose.

I've added netfilter folks in CC, it would be good to have feedback from them.

For new people, here is the thread:
http://www.spinics.net/lists/netdev/msg392031.html


Regards,
Nicolas

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-09-01 13:25     ` David Lebrun
@ 2016-09-01 17:15       ` Stephen Hemminger
  0 siblings, 0 replies; 26+ messages in thread
From: Stephen Hemminger @ 2016-09-01 17:15 UTC (permalink / raw)
  To: David Lebrun; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 458 bytes --]

On Thu, 1 Sep 2016 15:25:14 +0200
David Lebrun <david.lebrun@uclouvain.be> wrote:

> On 08/31/2016 07:10 PM, Stephen Hemminger wrote:
> > Since these are for control operations why a mutex?  
> 
> I am not sure to understand the question. The spinlock is used on the
> RCU write side of the namespace-wide parameters to prevent concurrent
> writes.
> 
> David
> 

If this lock is only being acquired in user context, then use a mutex
instead.

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
  2016-09-01 13:21     ` David Lebrun
@ 2016-09-05 10:05       ` Nicolas Dichtel
  0 siblings, 0 replies; 26+ messages in thread
From: Nicolas Dichtel @ 2016-09-05 10:05 UTC (permalink / raw)
  To: David Lebrun, Roopa Prabhu; +Cc: netdev

Le 01/09/2016 à 15:21, David Lebrun a écrit :
> On 08/29/2016 05:31 PM, Roopa Prabhu wrote:
>> This looks fine. But, i am just trying to see if this can be rtnetlink.
>> Have you considered it already ?.
>> We would like to keep the API consistent or abstracted to accommodate SR-MPLS in the
>> future too. so, any abstraction there will help.
>>
>> what is your control-plane software using this ?
>> quagga or any-other routing daemon ?
>>
>> Thanks,
>> Roopa
>>
> 
> rtnetlink is used for the routing part through the lwtunnels. In this
> specific patch, the API is intended to configure namespace-wide
> parameters such as a map of hmackeyid -> hashfn,secret, without
> connection to particular routes. I agree that the tunsrc parameter could
> be provided through rtnetlink, but the hmac data cannot (which by the
> way does not exist for SR-MPLS).
But it's closely related to routes. You can add a new family RTM_foo. It will be
easier to implement userspace part (only one netlink family is involved).


Regards,
Nicolas

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2016-09-05 10:06 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-08-26 15:52 [RFC 0/9] add support for IPv6 Segment Routing David Lebrun
2016-08-26 15:52 ` [RFC 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header) David Lebrun
2016-08-31 14:51   ` Nicolas Dichtel
2016-09-01 13:11     ` David Lebrun
2016-09-01 13:58       ` Nicolas Dichtel
2016-08-31 17:13   ` Stephen Hemminger
2016-08-26 15:52 ` [RFC 2/9] ipv6: sr: add code base for control plane support of SR-IPv6 David Lebrun
2016-08-29 15:31   ` Roopa Prabhu
2016-08-31 14:57     ` Nicolas Dichtel
2016-09-01 13:21     ` David Lebrun
2016-09-05 10:05       ` Nicolas Dichtel
2016-08-31 14:59   ` Nicolas Dichtel
2016-08-31 17:10   ` Stephen Hemminger
2016-09-01 13:25     ` David Lebrun
2016-09-01 17:15       ` Stephen Hemminger
2016-08-31 17:11   ` Stephen Hemminger
2016-08-31 17:11   ` Stephen Hemminger
2016-08-26 15:52 ` [RFC 3/9] ipv6: route: export symbol ip6_route_input David Lebrun
2016-08-26 15:52 ` [RFC 4/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels David Lebrun
2016-08-29 14:52   ` Roopa Prabhu
2016-09-01 13:32     ` David Lebrun
2016-08-26 15:54 ` [RFC 5/9] ipv6: sr: add core files for SR HMAC support David Lebrun
2016-08-26 15:54 ` [RFC 6/9] ipv6: sr: implement API to control SR HMAC structures David Lebrun
2016-08-26 15:54 ` [RFC 7/9] ipv6: sr: add calls to verify and insert HMAC signatures David Lebrun
2016-08-26 15:54 ` [RFC 8/9] ipv6: add source address argument for ipv6_push_nfrag_opts David Lebrun
2016-08-26 15:54 ` [RFC 9/9] ipv6: sr: add support for SRH injection through setsockopt David Lebrun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).