Commit f8045ca9 authored by David S. Miller's avatar David S. Miller

Merge branch 'nsh-headers-GSO'

Jiri Benc says:

====================
nsh: headers, GSO

This adds header structs and helpers for NSH together with GSO support.

Note there is no code in this patchset that actually manipulates the NSH
headers. That was sent to netdev by Yi Yang ("[PATCH net-next v6 0/3]
openvswitch: add NSH support"). The aim of this series is to lay the
groundwork and ease the implementation for him.

In addition to openvswitch, the NSH support should be added to tc (flower to
match, act_nsh to push/pop NSH headers). That will come later. There's
currently no plan to support NSH by other means than those two.

The patch 3 in this patchset was written by Yi Yang, I took it from the
aforementioned series and slightly modified it - see the note in the patch.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 13a6fad8 c411ed85
......@@ -26,6 +26,7 @@
#include <net/inet_ecn.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/tun_proto.h>
#include <net/vxlan.h>
#if IS_ENABLED(CONFIG_IPV6)
......@@ -1261,19 +1262,9 @@ static bool vxlan_parse_gpe_hdr(struct vxlanhdr *unparsed,
if (gpe->oam_flag)
return false;
switch (gpe->next_protocol) {
case VXLAN_GPE_NP_IPV4:
*protocol = htons(ETH_P_IP);
break;
case VXLAN_GPE_NP_IPV6:
*protocol = htons(ETH_P_IPV6);
break;
case VXLAN_GPE_NP_ETHERNET:
*protocol = htons(ETH_P_TEB);
break;
default:
*protocol = tun_p_to_eth_p(gpe->next_protocol);
if (!*protocol)
return false;
}
unparsed->vx_flags &= ~VXLAN_GPE_USED_BITS;
return true;
......@@ -1799,19 +1790,10 @@ static int vxlan_build_gpe_hdr(struct vxlanhdr *vxh, u32 vxflags,
struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)vxh;
gpe->np_applied = 1;
switch (protocol) {
case htons(ETH_P_IP):
gpe->next_protocol = VXLAN_GPE_NP_IPV4;
return 0;
case htons(ETH_P_IPV6):
gpe->next_protocol = VXLAN_GPE_NP_IPV6;
return 0;
case htons(ETH_P_TEB):
gpe->next_protocol = VXLAN_GPE_NP_ETHERNET;
return 0;
}
gpe->next_protocol = tun_p_from_eth_p(protocol);
if (!gpe->next_protocol)
return -EPFNOSUPPORT;
return 0;
}
static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
......
This diff is collapsed.
#ifndef __NET_TUN_PROTO_H
#define __NET_TUN_PROTO_H
#include <linux/kernel.h>
/* One byte protocol values as defined by VXLAN-GPE and NSH. These will
* hopefully get a shared IANA registry.
*/
#define TUN_P_IPV4 0x01
#define TUN_P_IPV6 0x02
#define TUN_P_ETHERNET 0x03
#define TUN_P_NSH 0x04
#define TUN_P_MPLS_UC 0x05
static inline __be16 tun_p_to_eth_p(u8 proto)
{
switch (proto) {
case TUN_P_IPV4:
return htons(ETH_P_IP);
case TUN_P_IPV6:
return htons(ETH_P_IPV6);
case TUN_P_ETHERNET:
return htons(ETH_P_TEB);
case TUN_P_NSH:
return htons(ETH_P_NSH);
case TUN_P_MPLS_UC:
return htons(ETH_P_MPLS_UC);
}
return 0;
}
static inline u8 tun_p_from_eth_p(__be16 proto)
{
switch (proto) {
case htons(ETH_P_IP):
return TUN_P_IPV4;
case htons(ETH_P_IPV6):
return TUN_P_IPV6;
case htons(ETH_P_TEB):
return TUN_P_ETHERNET;
case htons(ETH_P_NSH):
return TUN_P_NSH;
case htons(ETH_P_MPLS_UC):
return TUN_P_MPLS_UC;
}
return 0;
}
#endif
......@@ -168,12 +168,6 @@ reserved_flags2:2;
#define VXLAN_GPE_USED_BITS (VXLAN_HF_VER | VXLAN_HF_NP | VXLAN_HF_OAM | \
cpu_to_be32(0xff))
/* VXLAN-GPE header Next Protocol. */
#define VXLAN_GPE_NP_IPV4 0x01
#define VXLAN_GPE_NP_IPV6 0x02
#define VXLAN_GPE_NP_ETHERNET 0x03
#define VXLAN_GPE_NP_NSH 0x04
struct vxlan_metadata {
u32 gbp;
};
......
......@@ -99,6 +99,7 @@
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */
#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */
#define ETH_P_NSH 0x894F /* Network Service Header */
#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
......
......@@ -235,6 +235,7 @@ source "net/openvswitch/Kconfig"
source "net/vmw_vsock/Kconfig"
source "net/netlink/Kconfig"
source "net/mpls/Kconfig"
source "net/nsh/Kconfig"
source "net/hsr/Kconfig"
source "net/switchdev/Kconfig"
source "net/l3mdev/Kconfig"
......
......@@ -75,6 +75,7 @@ obj-$(CONFIG_NET_IFE) += ife/
obj-$(CONFIG_OPENVSWITCH) += openvswitch/
obj-$(CONFIG_VSOCKETS) += vmw_vsock/
obj-$(CONFIG_MPLS) += mpls/
obj-$(CONFIG_NET_NSH) += nsh/
obj-$(CONFIG_HSR) += hsr/
ifneq ($(CONFIG_NET_SWITCHDEV),)
obj-y += switchdev/
......
menuconfig NET_NSH
tristate "Network Service Header (NSH) protocol"
default n
---help---
Network Service Header is an implementation of Service Function
Chaining (RFC 7665). The current implementation in Linux supports
only MD type 1 and only with the openvswitch module.
If unsure, say N.
obj-$(CONFIG_NET_NSH) += nsh.o
/*
* Network Service Header
*
* Copyright (c) 2017 Red Hat, Inc. -- Jiri Benc <jbenc@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/nsh.h>
#include <net/tun_proto.h>
static struct sk_buff *nsh_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
unsigned int nsh_len, mac_len;
__be16 proto;
int nhoff;
skb_reset_network_header(skb);
nhoff = skb->network_header - skb->mac_header;
mac_len = skb->mac_len;
if (unlikely(!pskb_may_pull(skb, NSH_BASE_HDR_LEN)))
goto out;
nsh_len = nsh_hdr_len(nsh_hdr(skb));
if (unlikely(!pskb_may_pull(skb, nsh_len)))
goto out;
proto = tun_p_to_eth_p(nsh_hdr(skb)->np);
if (!proto)
goto out;
__skb_pull(skb, nsh_len);
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);
skb->protocol = proto;
features &= NETIF_F_SG;
segs = skb_mac_gso_segment(skb, features);
if (IS_ERR_OR_NULL(segs)) {
skb_gso_error_unwind(skb, htons(ETH_P_NSH), nsh_len,
skb->network_header - nhoff,
mac_len);
goto out;
}
for (skb = segs; skb; skb = skb->next) {
skb->protocol = htons(ETH_P_NSH);
__skb_push(skb, nsh_len);
skb_set_mac_header(skb, -nhoff);
skb->network_header = skb->mac_header + mac_len;
skb->mac_len = mac_len;
}
out:
return segs;
}
static struct packet_offload nsh_packet_offload __read_mostly = {
.type = htons(ETH_P_NSH),
.priority = 15,
.callbacks = {
.gso_segment = nsh_gso_segment,
},
};
static int __init nsh_init_module(void)
{
dev_add_offload(&nsh_packet_offload);
return 0;
}
static void __exit nsh_cleanup_module(void)
{
dev_remove_offload(&nsh_packet_offload);
}
module_init(nsh_init_module);
module_exit(nsh_cleanup_module);
MODULE_AUTHOR("Jiri Benc <jbenc@redhat.com>");
MODULE_DESCRIPTION("NSH protocol");
MODULE_LICENSE("GPL v2");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment