Skip to content

Commit

Permalink
datapath: enable NSH support
Browse files Browse the repository at this point in the history
Upstream commit:
  commit b2d0f5d5dc53532e6f07bc546a476a55ebdfe0f3
  Author: Yi Yang <[email protected]>
  Date:   Tue Nov 7 21:07:02 2017 +0800

    openvswitch: enable NSH support

    OVS master and 2.8 branch has merged NSH userspace
    patch series, this patch is to enable NSH support
    in kernel data path in order that OVS can support
    NSH in compat mode by porting this.

    Signed-off-by: Yi Yang <[email protected]>
    Acked-by: Jiri Benc <[email protected]>
    Acked-by: Eric Garver <[email protected]>
    Acked-by: Pravin Shelar <[email protected]>
    Signed-off-by: David S. Miller <[email protected]>

Signed-off-by: Yi Yang <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
Reviewed-by: Greg Rose <[email protected]>
  • Loading branch information
yi-y-yang authored and blp committed Feb 7, 2018
1 parent 907c26a commit 96b82f6
Show file tree
Hide file tree
Showing 11 changed files with 684 additions and 5 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ v2.9.0 - xx xxx xxxx
- NSH implementation now conforms to latest draft (draft-ietf-sfc-nsh-28).
* Add ttl field.
* Add a new action dec_nsh_ttl.
* Enable NSH support in kernel datapath.
- OVSDB:
* New high-level documentation in ovsdb(7).
* New file format documentation for developers in ovsdb(5).
Expand Down
1 change: 1 addition & 0 deletions acinclude.m4
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_get_by_index_rcu])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_recursion_level])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [__skb_gso_segment])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [skb_gso_error_unwind])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [can_checksum_protocol])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [ndo_get_iflink])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [ndo_features_check],
Expand Down
116 changes: 116 additions & 0 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "conntrack.h"
#include "gso.h"
#include "vport.h"
#include "flow_netlink.h"

static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key,
Expand Down Expand Up @@ -385,6 +386,38 @@ static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
return 0;
}

static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key,
const struct nshhdr *nh)
{
int err;

err = ovs_nsh_push(skb, nh);
if (err)
return err;

/* safe right before invalidate_flow_key */
key->mac_proto = MAC_PROTO_NONE;
invalidate_flow_key(key);
return 0;
}

static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
{
int err;

err = ovs_nsh_pop(skb);
if (err)
return err;

/* safe right before invalidate_flow_key */
if (skb->protocol == htons(ETH_P_TEB))
key->mac_proto = MAC_PROTO_ETHERNET;
else
key->mac_proto = MAC_PROTO_NONE;
invalidate_flow_key(key);
return 0;
}

static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
__be32 addr, __be32 new_addr)
{
Expand Down Expand Up @@ -608,6 +641,69 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
return 0;
}

static int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key,
const struct nlattr *a)
{
struct nshhdr *nh;
size_t length;
int err;
u8 flags;
u8 ttl;
int i;

struct ovs_key_nsh key;
struct ovs_key_nsh mask;

err = nsh_key_from_nlattr(a, &key, &mask);
if (err)
return err;

/* Make sure the NSH base header is there */
if (!pskb_may_pull(skb, skb_network_offset(skb) + NSH_BASE_HDR_LEN))
return -ENOMEM;

nh = nsh_hdr(skb);
length = nsh_hdr_len(nh);

/* Make sure the whole NSH header is there */
err = skb_ensure_writable(skb, skb_network_offset(skb) +
length);
if (unlikely(err))
return err;

nh = nsh_hdr(skb);
skb_postpull_rcsum(skb, nh, length);
flags = nsh_get_flags(nh);
flags = OVS_MASKED(flags, key.base.flags, mask.base.flags);
flow_key->nsh.base.flags = flags;
ttl = nsh_get_ttl(nh);
ttl = OVS_MASKED(ttl, key.base.ttl, mask.base.ttl);
flow_key->nsh.base.ttl = ttl;
nsh_set_flags_and_ttl(nh, flags, ttl);
nh->path_hdr = OVS_MASKED(nh->path_hdr, key.base.path_hdr,
mask.base.path_hdr);
flow_key->nsh.base.path_hdr = nh->path_hdr;
switch (nh->mdtype) {
case NSH_M_TYPE1:
for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) {
nh->md1.context[i] =
OVS_MASKED(nh->md1.context[i], key.context[i],
mask.context[i]);
}
memcpy(flow_key->nsh.context, nh->md1.context,
sizeof(nh->md1.context));
break;
case NSH_M_TYPE2:
memset(flow_key->nsh.context, 0,
sizeof(flow_key->nsh.context));
break;
default:
return -EINVAL;
}
skb_postpush_rcsum(skb, nh, length);
return 0;
}

/* Must follow skb_ensure_writable() since that can move the skb data. */
static void set_tp_port(struct sk_buff *skb, __be16 *port,
__be16 new_port, __sum16 *check)
Expand Down Expand Up @@ -1035,6 +1131,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
get_mask(a, struct ovs_key_ethernet *));
break;

case OVS_KEY_ATTR_NSH:
err = set_nsh(skb, flow_key, a);
break;

case OVS_KEY_ATTR_IPV4:
err = set_ipv4(skb, flow_key, nla_data(a),
get_mask(a, struct ovs_key_ipv4 *));
Expand Down Expand Up @@ -1225,6 +1325,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
case OVS_ACTION_ATTR_POP_ETH:
err = pop_eth(skb, key);
break;

case OVS_ACTION_ATTR_PUSH_NSH: {
u8 buffer[NSH_HDR_MAX_LEN];
struct nshhdr *nh = (struct nshhdr *)buffer;

err = nsh_hdr_from_nlattr(nla_data(a), nh,
NSH_HDR_MAX_LEN);
if (unlikely(err))
break;
err = push_nsh(skb, key, nh);
break;
}

case OVS_ACTION_ATTR_POP_NSH:
err = pop_nsh(skb, key);
break;
}

if (unlikely(err)) {
Expand Down
51 changes: 51 additions & 0 deletions datapath/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <net/ipv6.h>
#include <net/mpls.h>
#include <net/ndisc.h>
#include <net/nsh.h>

#include "datapath.h"
#include "conntrack.h"
Expand Down Expand Up @@ -494,6 +495,52 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
return 0;
}

static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
{
struct nshhdr *nh;
unsigned int nh_ofs = skb_network_offset(skb);
u8 version, length;
int err;

err = check_header(skb, nh_ofs + NSH_BASE_HDR_LEN);
if (unlikely(err))
return err;

nh = nsh_hdr(skb);
version = nsh_get_ver(nh);
length = nsh_hdr_len(nh);

if (version != 0)
return -EINVAL;

err = check_header(skb, nh_ofs + length);
if (unlikely(err))
return err;

nh = nsh_hdr(skb);
key->nsh.base.flags = nsh_get_flags(nh);
key->nsh.base.ttl = nsh_get_ttl(nh);
key->nsh.base.mdtype = nh->mdtype;
key->nsh.base.np = nh->np;
key->nsh.base.path_hdr = nh->path_hdr;
switch (key->nsh.base.mdtype) {
case NSH_M_TYPE1:
if (length != NSH_M_TYPE1_LEN)
return -EINVAL;
memcpy(key->nsh.context, nh->md1.context,
sizeof(nh->md1));
break;
case NSH_M_TYPE2:
memset(key->nsh.context, 0,
sizeof(nh->md1));
break;
default:
return -EINVAL;
}

return 0;
}

/**
* key_extract - extracts a flow key from an Ethernet frame.
* @skb: sk_buff that contains the frame, with skb->data pointing to the
Expand Down Expand Up @@ -751,6 +798,10 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
memset(&key->tp, 0, sizeof(key->tp));
}
}
} else if (key->eth.type == htons(ETH_P_NSH)) {
error = parse_nsh(skb, key);
if (error)
return error;
}
return 0;
}
Expand Down
7 changes: 7 additions & 0 deletions datapath/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <net/inet_ecn.h>
#include <net/ip_tunnels.h>
#include <net/dst_metadata.h>
#include <net/nsh.h>

struct sk_buff;

Expand Down Expand Up @@ -66,6 +67,11 @@ struct vlan_head {
(offsetof(struct sw_flow_key, recirc_id) + \
FIELD_SIZEOF(struct sw_flow_key, recirc_id))

struct ovs_key_nsh {
struct ovs_nsh_key_base base;
__be32 context[NSH_MD1_CONTEXT_SIZE];
};

struct sw_flow_key {
u8 tun_opts[255];
u8 tun_opts_len;
Expand Down Expand Up @@ -143,6 +149,7 @@ struct sw_flow_key {
} nd;
};
} ipv6;
struct ovs_key_nsh nsh; /* network service header */
};
struct {
/* Connection tracking fields not packed above. */
Expand Down
Loading

0 comments on commit 96b82f6

Please sign in to comment.