aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYi Yang <yi.y.yang@intel.com>2017-11-07 08:07:02 -0500
committerDavid S. Miller <davem@davemloft.net>2017-11-08 02:12:33 -0500
commitb2d0f5d5dc53532e6f07bc546a476a55ebdfe0f3 (patch)
tree120c5e89b96cc86a85c77e81cdbb42c3db08cc70
parent7f5d3f2721b07ab5896526c5992edd2ab1665561 (diff)
openvswitch: enable NSH support
v16->17 - Fixed disputed check code: keep them in nsh_push and nsh_pop but also add them in __ovs_nla_copy_actions v15->v16 - Add csum recalculation for nsh_push, nsh_pop and set_nsh pointed out by Pravin - Move nsh key into the union with ipv4 and ipv6 and add check for nsh key in match_validate pointed out by Pravin - Add nsh check in validate_set and __ovs_nla_copy_actions v14->v15 - Check size in nsh_hdr_from_nlattr - Fixed four small issues pointed out By Jiri and Eric v13->v14 - Rename skb_push_nsh to nsh_push per Dave's comment - Rename skb_pop_nsh to nsh_pop per Dave's comment v12->v13 - Fix NSH header length check in set_nsh v11->v12 - Fix missing changes old comments pointed out - Fix new comments for v11 v10->v11 - Fix the left three disputable comments for v9 but not fixed in v10. v9->v10 - Change struct ovs_key_nsh to struct ovs_nsh_key_base base; __be32 context[NSH_MD1_CONTEXT_SIZE]; - Fix new comments for v9 v8->v9 - Fix build error reported by daily intel build because nsh module isn't selected by openvswitch v7->v8 - Rework nested value and mask for OVS_KEY_ATTR_NSH - Change pop_nsh to adapt to nsh kernel module - Fix many issues per comments from Jiri Benc v6->v7 - Remove NSH GSO patches in v6 because Jiri Benc reworked it as another patch series and they have been merged. - Change it to adapt to nsh kernel module added by NSH GSO patch series v5->v6 - Fix the rest comments for v4. - Add NSH GSO support for VxLAN-gpe + NSH and Eth + NSH. v4->v5 - Fix many comments by Jiri Benc and Eric Garver for v4. v3->v4 - Add new NSH match field ttl - Update NSH header to the latest format which will be final format and won't change per its author's confirmation. - Fix comments for v3. v2->v3 - Change OVS_KEY_ATTR_NSH to nested key to handle length-fixed attributes and length-variable attriubte more flexibly. - Remove struct ovs_action_push_nsh completely - Add code to handle nested attribute for SET_MASKED - Change PUSH_NSH to use the nested OVS_KEY_ATTR_NSH to transfer NSH header data. - Fix comments and coding style issues by Jiri and Eric v1->v2 - Change encap_nsh and decap_nsh to push_nsh and pop_nsh - Dynamically allocate struct ovs_action_push_nsh for length-variable metadata. 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 <yi.y.yang@intel.com> Acked-by: Jiri Benc <jbenc@redhat.com> Acked-by: Eric Garver <e@erig.me> Acked-by: Pravin Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/nsh.h3
-rw-r--r--include/uapi/linux/openvswitch.h29
-rw-r--r--net/nsh/nsh.c60
-rw-r--r--net/openvswitch/Kconfig1
-rw-r--r--net/openvswitch/actions.c116
-rw-r--r--net/openvswitch/flow.c51
-rw-r--r--net/openvswitch/flow.h7
-rw-r--r--net/openvswitch/flow_netlink.c343
-rw-r--r--net/openvswitch/flow_netlink.h5
9 files changed, 613 insertions, 2 deletions
diff --git a/include/net/nsh.h b/include/net/nsh.h
index a1eaea20be96..350b1ad11c7f 100644
--- a/include/net/nsh.h
+++ b/include/net/nsh.h
@@ -304,4 +304,7 @@ static inline void nsh_set_flags_ttl_len(struct nshhdr *nsh, u8 flags,
304 NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK); 304 NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK);
305} 305}
306 306
307int nsh_push(struct sk_buff *skb, const struct nshhdr *pushed_nh);
308int nsh_pop(struct sk_buff *skb);
309
307#endif /* __NET_NSH_H */ 310#endif /* __NET_NSH_H */
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 501e4c4e2a03..ec75a685f1dd 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -336,6 +336,7 @@ enum ovs_key_attr {
336 OVS_KEY_ATTR_CT_LABELS, /* 16-octet connection tracking label */ 336 OVS_KEY_ATTR_CT_LABELS, /* 16-octet connection tracking label */
337 OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4, /* struct ovs_key_ct_tuple_ipv4 */ 337 OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4, /* struct ovs_key_ct_tuple_ipv4 */
338 OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6, /* struct ovs_key_ct_tuple_ipv6 */ 338 OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6, /* struct ovs_key_ct_tuple_ipv6 */
339 OVS_KEY_ATTR_NSH, /* Nested set of ovs_nsh_key_* */
339 340
340#ifdef __KERNEL__ 341#ifdef __KERNEL__
341 OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ 342 OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */
@@ -495,6 +496,30 @@ struct ovs_key_ct_tuple_ipv6 {
495 __u8 ipv6_proto; 496 __u8 ipv6_proto;
496}; 497};
497 498
499enum ovs_nsh_key_attr {
500 OVS_NSH_KEY_ATTR_UNSPEC,
501 OVS_NSH_KEY_ATTR_BASE, /* struct ovs_nsh_key_base. */
502 OVS_NSH_KEY_ATTR_MD1, /* struct ovs_nsh_key_md1. */
503 OVS_NSH_KEY_ATTR_MD2, /* variable-length octets for MD type 2. */
504 __OVS_NSH_KEY_ATTR_MAX
505};
506
507#define OVS_NSH_KEY_ATTR_MAX (__OVS_NSH_KEY_ATTR_MAX - 1)
508
509struct ovs_nsh_key_base {
510 __u8 flags;
511 __u8 ttl;
512 __u8 mdtype;
513 __u8 np;
514 __be32 path_hdr;
515};
516
517#define NSH_MD1_CONTEXT_SIZE 4
518
519struct ovs_nsh_key_md1 {
520 __be32 context[NSH_MD1_CONTEXT_SIZE];
521};
522
498/** 523/**
499 * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands. 524 * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
500 * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow 525 * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
@@ -811,6 +836,8 @@ struct ovs_action_push_eth {
811 * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the 836 * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the
812 * packet. 837 * packet.
813 * @OVS_ACTION_ATTR_CT_CLEAR: Clear conntrack state from the packet. 838 * @OVS_ACTION_ATTR_CT_CLEAR: Clear conntrack state from the packet.
839 * @OVS_ACTION_ATTR_PUSH_NSH: push NSH header to the packet.
840 * @OVS_ACTION_ATTR_POP_NSH: pop the outermost NSH header off the packet.
814 * 841 *
815 * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all 842 * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
816 * fields within a header are modifiable, e.g. the IPv4 protocol and fragment 843 * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -841,6 +868,8 @@ enum ovs_action_attr {
841 OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */ 868 OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */
842 OVS_ACTION_ATTR_POP_ETH, /* No argument. */ 869 OVS_ACTION_ATTR_POP_ETH, /* No argument. */
843 OVS_ACTION_ATTR_CT_CLEAR, /* No argument. */ 870 OVS_ACTION_ATTR_CT_CLEAR, /* No argument. */
871 OVS_ACTION_ATTR_PUSH_NSH, /* Nested OVS_NSH_KEY_ATTR_*. */
872 OVS_ACTION_ATTR_POP_NSH, /* No argument. */
844 873
845 __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted 874 __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
846 * from userspace. */ 875 * from userspace. */
diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c
index 58fb827439a8..d7da99a0b0b8 100644
--- a/net/nsh/nsh.c
+++ b/net/nsh/nsh.c
@@ -14,6 +14,66 @@
14#include <net/nsh.h> 14#include <net/nsh.h>
15#include <net/tun_proto.h> 15#include <net/tun_proto.h>
16 16
17int nsh_push(struct sk_buff *skb, const struct nshhdr *pushed_nh)
18{
19 struct nshhdr *nh;
20 size_t length = nsh_hdr_len(pushed_nh);
21 u8 next_proto;
22
23 if (skb->mac_len) {
24 next_proto = TUN_P_ETHERNET;
25 } else {
26 next_proto = tun_p_from_eth_p(skb->protocol);
27 if (!next_proto)
28 return -EAFNOSUPPORT;
29 }
30
31 /* Add the NSH header */
32 if (skb_cow_head(skb, length) < 0)
33 return -ENOMEM;
34
35 skb_push(skb, length);
36 nh = (struct nshhdr *)(skb->data);
37 memcpy(nh, pushed_nh, length);
38 nh->np = next_proto;
39 skb_postpush_rcsum(skb, nh, length);
40
41 skb->protocol = htons(ETH_P_NSH);
42 skb_reset_mac_header(skb);
43 skb_reset_network_header(skb);
44 skb_reset_mac_len(skb);
45
46 return 0;
47}
48EXPORT_SYMBOL_GPL(nsh_push);
49
50int nsh_pop(struct sk_buff *skb)
51{
52 struct nshhdr *nh;
53 size_t length;
54 __be16 inner_proto;
55
56 if (!pskb_may_pull(skb, NSH_BASE_HDR_LEN))
57 return -ENOMEM;
58 nh = (struct nshhdr *)(skb->data);
59 length = nsh_hdr_len(nh);
60 inner_proto = tun_p_to_eth_p(nh->np);
61 if (!pskb_may_pull(skb, length))
62 return -ENOMEM;
63
64 if (!inner_proto)
65 return -EAFNOSUPPORT;
66
67 skb_pull_rcsum(skb, length);
68 skb_reset_mac_header(skb);
69 skb_reset_network_header(skb);
70 skb_reset_mac_len(skb);
71 skb->protocol = inner_proto;
72
73 return 0;
74}
75EXPORT_SYMBOL_GPL(nsh_pop);
76
17static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, 77static struct sk_buff *nsh_gso_segment(struct sk_buff *skb,
18 netdev_features_t features) 78 netdev_features_t features)
19{ 79{
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig
index ce947292ae77..2650205cdaf9 100644
--- a/net/openvswitch/Kconfig
+++ b/net/openvswitch/Kconfig
@@ -14,6 +14,7 @@ config OPENVSWITCH
14 select MPLS 14 select MPLS
15 select NET_MPLS_GSO 15 select NET_MPLS_GSO
16 select DST_CACHE 16 select DST_CACHE
17 select NET_NSH
17 ---help--- 18 ---help---
18 Open vSwitch is a multilayer Ethernet switch targeted at virtualized 19 Open vSwitch is a multilayer Ethernet switch targeted at virtualized
19 environments. In addition to supporting a variety of features 20 environments. In addition to supporting a variety of features
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index a551232daf61..9a6a6d51e421 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -43,6 +43,7 @@
43#include "flow.h" 43#include "flow.h"
44#include "conntrack.h" 44#include "conntrack.h"
45#include "vport.h" 45#include "vport.h"
46#include "flow_netlink.h"
46 47
47struct deferred_action { 48struct deferred_action {
48 struct sk_buff *skb; 49 struct sk_buff *skb;
@@ -380,6 +381,38 @@ static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
380 return 0; 381 return 0;
381} 382}
382 383
384static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key,
385 const struct nshhdr *nh)
386{
387 int err;
388
389 err = nsh_push(skb, nh);
390 if (err)
391 return err;
392
393 /* safe right before invalidate_flow_key */
394 key->mac_proto = MAC_PROTO_NONE;
395 invalidate_flow_key(key);
396 return 0;
397}
398
399static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
400{
401 int err;
402
403 err = nsh_pop(skb);
404 if (err)
405 return err;
406
407 /* safe right before invalidate_flow_key */
408 if (skb->protocol == htons(ETH_P_TEB))
409 key->mac_proto = MAC_PROTO_ETHERNET;
410 else
411 key->mac_proto = MAC_PROTO_NONE;
412 invalidate_flow_key(key);
413 return 0;
414}
415
383static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh, 416static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
384 __be32 addr, __be32 new_addr) 417 __be32 addr, __be32 new_addr)
385{ 418{
@@ -602,6 +635,69 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
602 return 0; 635 return 0;
603} 636}
604 637
638static int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key,
639 const struct nlattr *a)
640{
641 struct nshhdr *nh;
642 size_t length;
643 int err;
644 u8 flags;
645 u8 ttl;
646 int i;
647
648 struct ovs_key_nsh key;
649 struct ovs_key_nsh mask;
650
651 err = nsh_key_from_nlattr(a, &key, &mask);
652 if (err)
653 return err;
654
655 /* Make sure the NSH base header is there */
656 if (!pskb_may_pull(skb, skb_network_offset(skb) + NSH_BASE_HDR_LEN))
657 return -ENOMEM;
658
659 nh = nsh_hdr(skb);
660 length = nsh_hdr_len(nh);
661
662 /* Make sure the whole NSH header is there */
663 err = skb_ensure_writable(skb, skb_network_offset(skb) +
664 length);
665 if (unlikely(err))
666 return err;
667
668 nh = nsh_hdr(skb);
669 skb_postpull_rcsum(skb, nh, length);
670 flags = nsh_get_flags(nh);
671 flags = OVS_MASKED(flags, key.base.flags, mask.base.flags);
672 flow_key->nsh.base.flags = flags;
673 ttl = nsh_get_ttl(nh);
674 ttl = OVS_MASKED(ttl, key.base.ttl, mask.base.ttl);
675 flow_key->nsh.base.ttl = ttl;
676 nsh_set_flags_and_ttl(nh, flags, ttl);
677 nh->path_hdr = OVS_MASKED(nh->path_hdr, key.base.path_hdr,
678 mask.base.path_hdr);
679 flow_key->nsh.base.path_hdr = nh->path_hdr;
680 switch (nh->mdtype) {
681 case NSH_M_TYPE1:
682 for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) {
683 nh->md1.context[i] =
684 OVS_MASKED(nh->md1.context[i], key.context[i],
685 mask.context[i]);
686 }
687 memcpy(flow_key->nsh.context, nh->md1.context,
688 sizeof(nh->md1.context));
689 break;
690 case NSH_M_TYPE2:
691 memset(flow_key->nsh.context, 0,
692 sizeof(flow_key->nsh.context));
693 break;
694 default:
695 return -EINVAL;
696 }
697 skb_postpush_rcsum(skb, nh, length);
698 return 0;
699}
700
605/* Must follow skb_ensure_writable() since that can move the skb data. */ 701/* Must follow skb_ensure_writable() since that can move the skb data. */
606static void set_tp_port(struct sk_buff *skb, __be16 *port, 702static void set_tp_port(struct sk_buff *skb, __be16 *port,
607 __be16 new_port, __sum16 *check) 703 __be16 new_port, __sum16 *check)
@@ -1024,6 +1120,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
1024 get_mask(a, struct ovs_key_ethernet *)); 1120 get_mask(a, struct ovs_key_ethernet *));
1025 break; 1121 break;
1026 1122
1123 case OVS_KEY_ATTR_NSH:
1124 err = set_nsh(skb, flow_key, a);
1125 break;
1126
1027 case OVS_KEY_ATTR_IPV4: 1127 case OVS_KEY_ATTR_IPV4:
1028 err = set_ipv4(skb, flow_key, nla_data(a), 1128 err = set_ipv4(skb, flow_key, nla_data(a),
1029 get_mask(a, struct ovs_key_ipv4 *)); 1129 get_mask(a, struct ovs_key_ipv4 *));
@@ -1214,6 +1314,22 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
1214 case OVS_ACTION_ATTR_POP_ETH: 1314 case OVS_ACTION_ATTR_POP_ETH:
1215 err = pop_eth(skb, key); 1315 err = pop_eth(skb, key);
1216 break; 1316 break;
1317
1318 case OVS_ACTION_ATTR_PUSH_NSH: {
1319 u8 buffer[NSH_HDR_MAX_LEN];
1320 struct nshhdr *nh = (struct nshhdr *)buffer;
1321
1322 err = nsh_hdr_from_nlattr(nla_data(a), nh,
1323 NSH_HDR_MAX_LEN);
1324 if (unlikely(err))
1325 break;
1326 err = push_nsh(skb, key, nh);
1327 break;
1328 }
1329
1330 case OVS_ACTION_ATTR_POP_NSH:
1331 err = pop_nsh(skb, key);
1332 break;
1217 } 1333 }
1218 1334
1219 if (unlikely(err)) { 1335 if (unlikely(err)) {
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 8c94cef25a72..864ddb1e3642 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -46,6 +46,7 @@
46#include <net/ipv6.h> 46#include <net/ipv6.h>
47#include <net/mpls.h> 47#include <net/mpls.h>
48#include <net/ndisc.h> 48#include <net/ndisc.h>
49#include <net/nsh.h>
49 50
50#include "conntrack.h" 51#include "conntrack.h"
51#include "datapath.h" 52#include "datapath.h"
@@ -490,6 +491,52 @@ invalid:
490 return 0; 491 return 0;
491} 492}
492 493
494static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
495{
496 struct nshhdr *nh;
497 unsigned int nh_ofs = skb_network_offset(skb);
498 u8 version, length;
499 int err;
500
501 err = check_header(skb, nh_ofs + NSH_BASE_HDR_LEN);
502 if (unlikely(err))
503 return err;
504
505 nh = nsh_hdr(skb);
506 version = nsh_get_ver(nh);
507 length = nsh_hdr_len(nh);
508
509 if (version != 0)
510 return -EINVAL;
511
512 err = check_header(skb, nh_ofs + length);
513 if (unlikely(err))
514 return err;
515
516 nh = nsh_hdr(skb);
517 key->nsh.base.flags = nsh_get_flags(nh);
518 key->nsh.base.ttl = nsh_get_ttl(nh);
519 key->nsh.base.mdtype = nh->mdtype;
520 key->nsh.base.np = nh->np;
521 key->nsh.base.path_hdr = nh->path_hdr;
522 switch (key->nsh.base.mdtype) {
523 case NSH_M_TYPE1:
524 if (length != NSH_M_TYPE1_LEN)
525 return -EINVAL;
526 memcpy(key->nsh.context, nh->md1.context,
527 sizeof(nh->md1));
528 break;
529 case NSH_M_TYPE2:
530 memset(key->nsh.context, 0,
531 sizeof(nh->md1));
532 break;
533 default:
534 return -EINVAL;
535 }
536
537 return 0;
538}
539
493/** 540/**
494 * key_extract - extracts a flow key from an Ethernet frame. 541 * key_extract - extracts a flow key from an Ethernet frame.
495 * @skb: sk_buff that contains the frame, with skb->data pointing to the 542 * @skb: sk_buff that contains the frame, with skb->data pointing to the
@@ -735,6 +782,10 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
735 memset(&key->tp, 0, sizeof(key->tp)); 782 memset(&key->tp, 0, sizeof(key->tp));
736 } 783 }
737 } 784 }
785 } else if (key->eth.type == htons(ETH_P_NSH)) {
786 error = parse_nsh(skb, key);
787 if (error)
788 return error;
738 } 789 }
739 return 0; 790 return 0;
740} 791}
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 1875bba4f865..c670dd24b8b7 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -35,6 +35,7 @@
35#include <net/inet_ecn.h> 35#include <net/inet_ecn.h>
36#include <net/ip_tunnels.h> 36#include <net/ip_tunnels.h>
37#include <net/dst_metadata.h> 37#include <net/dst_metadata.h>
38#include <net/nsh.h>
38 39
39struct sk_buff; 40struct sk_buff;
40 41
@@ -66,6 +67,11 @@ struct vlan_head {
66 (offsetof(struct sw_flow_key, recirc_id) + \ 67 (offsetof(struct sw_flow_key, recirc_id) + \
67 FIELD_SIZEOF(struct sw_flow_key, recirc_id)) 68 FIELD_SIZEOF(struct sw_flow_key, recirc_id))
68 69
70struct ovs_key_nsh {
71 struct ovs_nsh_key_base base;
72 __be32 context[NSH_MD1_CONTEXT_SIZE];
73};
74
69struct sw_flow_key { 75struct sw_flow_key {
70 u8 tun_opts[IP_TUNNEL_OPTS_MAX]; 76 u8 tun_opts[IP_TUNNEL_OPTS_MAX];
71 u8 tun_opts_len; 77 u8 tun_opts_len;
@@ -143,6 +149,7 @@ struct sw_flow_key {
143 } nd; 149 } nd;
144 }; 150 };
145 } ipv6; 151 } ipv6;
152 struct ovs_key_nsh nsh; /* network service header */
146 }; 153 };
147 struct { 154 struct {
148 /* Connection tracking fields not packed above. */ 155 /* Connection tracking fields not packed above. */
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index dc0d79092e74..4201f9293af3 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -48,6 +48,7 @@
48#include <net/ndisc.h> 48#include <net/ndisc.h>
49#include <net/mpls.h> 49#include <net/mpls.h>
50#include <net/vxlan.h> 50#include <net/vxlan.h>
51#include <net/tun_proto.h>
51#include <net/erspan.h> 52#include <net/erspan.h>
52 53
53#include "flow_netlink.h" 54#include "flow_netlink.h"
@@ -80,9 +81,11 @@ static bool actions_may_change_flow(const struct nlattr *actions)
80 case OVS_ACTION_ATTR_HASH: 81 case OVS_ACTION_ATTR_HASH:
81 case OVS_ACTION_ATTR_POP_ETH: 82 case OVS_ACTION_ATTR_POP_ETH:
82 case OVS_ACTION_ATTR_POP_MPLS: 83 case OVS_ACTION_ATTR_POP_MPLS:
84 case OVS_ACTION_ATTR_POP_NSH:
83 case OVS_ACTION_ATTR_POP_VLAN: 85 case OVS_ACTION_ATTR_POP_VLAN:
84 case OVS_ACTION_ATTR_PUSH_ETH: 86 case OVS_ACTION_ATTR_PUSH_ETH:
85 case OVS_ACTION_ATTR_PUSH_MPLS: 87 case OVS_ACTION_ATTR_PUSH_MPLS:
88 case OVS_ACTION_ATTR_PUSH_NSH:
86 case OVS_ACTION_ATTR_PUSH_VLAN: 89 case OVS_ACTION_ATTR_PUSH_VLAN:
87 case OVS_ACTION_ATTR_SAMPLE: 90 case OVS_ACTION_ATTR_SAMPLE:
88 case OVS_ACTION_ATTR_SET: 91 case OVS_ACTION_ATTR_SET:
@@ -175,7 +178,8 @@ static bool match_validate(const struct sw_flow_match *match,
175 | (1 << OVS_KEY_ATTR_ICMPV6) 178 | (1 << OVS_KEY_ATTR_ICMPV6)
176 | (1 << OVS_KEY_ATTR_ARP) 179 | (1 << OVS_KEY_ATTR_ARP)
177 | (1 << OVS_KEY_ATTR_ND) 180 | (1 << OVS_KEY_ATTR_ND)
178 | (1 << OVS_KEY_ATTR_MPLS)); 181 | (1 << OVS_KEY_ATTR_MPLS)
182 | (1 << OVS_KEY_ATTR_NSH));
179 183
180 /* Always allowed mask fields. */ 184 /* Always allowed mask fields. */
181 mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL) 185 mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL)
@@ -284,6 +288,14 @@ static bool match_validate(const struct sw_flow_match *match,
284 } 288 }
285 } 289 }
286 290
291 if (match->key->eth.type == htons(ETH_P_NSH)) {
292 key_expected |= 1 << OVS_KEY_ATTR_NSH;
293 if (match->mask &&
294 match->mask->key.eth.type == htons(0xffff)) {
295 mask_allowed |= 1 << OVS_KEY_ATTR_NSH;
296 }
297 }
298
287 if ((key_attrs & key_expected) != key_expected) { 299 if ((key_attrs & key_expected) != key_expected) {
288 /* Key attributes check failed. */ 300 /* Key attributes check failed. */
289 OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)", 301 OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)",
@@ -325,12 +337,25 @@ size_t ovs_tun_key_attr_size(void)
325 + nla_total_size(4); /* OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS */ 337 + nla_total_size(4); /* OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS */
326} 338}
327 339
340size_t ovs_nsh_key_attr_size(void)
341{
342 /* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider
343 * updating this function.
344 */
345 return nla_total_size(NSH_BASE_HDR_LEN) /* OVS_NSH_KEY_ATTR_BASE */
346 /* OVS_NSH_KEY_ATTR_MD1 and OVS_NSH_KEY_ATTR_MD2 are
347 * mutually exclusive, so the bigger one can cover
348 * the small one.
349 */
350 + nla_total_size(NSH_CTX_HDRS_MAX_LEN);
351}
352
328size_t ovs_key_attr_size(void) 353size_t ovs_key_attr_size(void)
329{ 354{
330 /* Whenever adding new OVS_KEY_ FIELDS, we should consider 355 /* Whenever adding new OVS_KEY_ FIELDS, we should consider
331 * updating this function. 356 * updating this function.
332 */ 357 */
333 BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 28); 358 BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 29);
334 359
335 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ 360 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
336 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ 361 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
@@ -344,6 +369,8 @@ size_t ovs_key_attr_size(void)
344 + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ 369 + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
345 + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */ 370 + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
346 + nla_total_size(40) /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */ 371 + nla_total_size(40) /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
372 + nla_total_size(0) /* OVS_KEY_ATTR_NSH */
373 + ovs_nsh_key_attr_size()
347 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ 374 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
348 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ 375 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
349 + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ 376 + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
@@ -377,6 +404,13 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
377 [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = sizeof(u32) }, 404 [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = sizeof(u32) },
378}; 405};
379 406
407static const struct ovs_len_tbl
408ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = {
409 [OVS_NSH_KEY_ATTR_BASE] = { .len = sizeof(struct ovs_nsh_key_base) },
410 [OVS_NSH_KEY_ATTR_MD1] = { .len = sizeof(struct ovs_nsh_key_md1) },
411 [OVS_NSH_KEY_ATTR_MD2] = { .len = OVS_ATTR_VARIABLE },
412};
413
380/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ 414/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
381static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { 415static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
382 [OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_NESTED }, 416 [OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_NESTED },
@@ -409,6 +443,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
409 .len = sizeof(struct ovs_key_ct_tuple_ipv4) }, 443 .len = sizeof(struct ovs_key_ct_tuple_ipv4) },
410 [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = { 444 [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {
411 .len = sizeof(struct ovs_key_ct_tuple_ipv6) }, 445 .len = sizeof(struct ovs_key_ct_tuple_ipv6) },
446 [OVS_KEY_ATTR_NSH] = { .len = OVS_ATTR_NESTED,
447 .next = ovs_nsh_key_attr_lens, },
412}; 448};
413 449
414static bool check_attr_len(unsigned int attr_len, unsigned int expected_len) 450static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
@@ -1227,6 +1263,221 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
1227 return 0; 1263 return 0;
1228} 1264}
1229 1265
1266int nsh_hdr_from_nlattr(const struct nlattr *attr,
1267 struct nshhdr *nh, size_t size)
1268{
1269 struct nlattr *a;
1270 int rem;
1271 u8 flags = 0;
1272 u8 ttl = 0;
1273 int mdlen = 0;
1274
1275 /* validate_nsh has check this, so we needn't do duplicate check here
1276 */
1277 if (size < NSH_BASE_HDR_LEN)
1278 return -ENOBUFS;
1279
1280 nla_for_each_nested(a, attr, rem) {
1281 int type = nla_type(a);
1282
1283 switch (type) {
1284 case OVS_NSH_KEY_ATTR_BASE: {
1285 const struct ovs_nsh_key_base *base = nla_data(a);
1286
1287 flags = base->flags;
1288 ttl = base->ttl;
1289 nh->np = base->np;
1290 nh->mdtype = base->mdtype;
1291 nh->path_hdr = base->path_hdr;
1292 break;
1293 }
1294 case OVS_NSH_KEY_ATTR_MD1:
1295 mdlen = nla_len(a);
1296 if (mdlen > size - NSH_BASE_HDR_LEN)
1297 return -ENOBUFS;
1298 memcpy(&nh->md1, nla_data(a), mdlen);
1299 break;
1300
1301 case OVS_NSH_KEY_ATTR_MD2:
1302 mdlen = nla_len(a);
1303 if (mdlen > size - NSH_BASE_HDR_LEN)
1304 return -ENOBUFS;
1305 memcpy(&nh->md2, nla_data(a), mdlen);
1306 break;
1307
1308 default:
1309 return -EINVAL;
1310 }
1311 }
1312
1313 /* nsh header length = NSH_BASE_HDR_LEN + mdlen */
1314 nh->ver_flags_ttl_len = 0;
1315 nsh_set_flags_ttl_len(nh, flags, ttl, NSH_BASE_HDR_LEN + mdlen);
1316
1317 return 0;
1318}
1319
1320int nsh_key_from_nlattr(const struct nlattr *attr,
1321 struct ovs_key_nsh *nsh, struct ovs_key_nsh *nsh_mask)
1322{
1323 struct nlattr *a;
1324 int rem;
1325
1326 /* validate_nsh has check this, so we needn't do duplicate check here
1327 */
1328 nla_for_each_nested(a, attr, rem) {
1329 int type = nla_type(a);
1330
1331 switch (type) {
1332 case OVS_NSH_KEY_ATTR_BASE: {
1333 const struct ovs_nsh_key_base *base = nla_data(a);
1334 const struct ovs_nsh_key_base *base_mask = base + 1;
1335
1336 nsh->base = *base;
1337 nsh_mask->base = *base_mask;
1338 break;
1339 }
1340 case OVS_NSH_KEY_ATTR_MD1: {
1341 const struct ovs_nsh_key_md1 *md1 = nla_data(a);
1342 const struct ovs_nsh_key_md1 *md1_mask = md1 + 1;
1343
1344 memcpy(nsh->context, md1->context, sizeof(*md1));
1345 memcpy(nsh_mask->context, md1_mask->context,
1346 sizeof(*md1_mask));
1347 break;
1348 }
1349 case OVS_NSH_KEY_ATTR_MD2:
1350 /* Not supported yet */
1351 return -ENOTSUPP;
1352 default:
1353 return -EINVAL;
1354 }
1355 }
1356
1357 return 0;
1358}
1359
1360static int nsh_key_put_from_nlattr(const struct nlattr *attr,
1361 struct sw_flow_match *match, bool is_mask,
1362 bool is_push_nsh, bool log)
1363{
1364 struct nlattr *a;
1365 int rem;
1366 bool has_base = false;
1367 bool has_md1 = false;
1368 bool has_md2 = false;
1369 u8 mdtype = 0;
1370 int mdlen = 0;
1371
1372 if (WARN_ON(is_push_nsh && is_mask))
1373 return -EINVAL;
1374
1375 nla_for_each_nested(a, attr, rem) {
1376 int type = nla_type(a);
1377 int i;
1378
1379 if (type > OVS_NSH_KEY_ATTR_MAX) {
1380 OVS_NLERR(log, "nsh attr %d is out of range max %d",
1381 type, OVS_NSH_KEY_ATTR_MAX);
1382 return -EINVAL;
1383 }
1384
1385 if (!check_attr_len(nla_len(a),
1386 ovs_nsh_key_attr_lens[type].len)) {
1387 OVS_NLERR(
1388 log,
1389 "nsh attr %d has unexpected len %d expected %d",
1390 type,
1391 nla_len(a),
1392 ovs_nsh_key_attr_lens[type].len
1393 );
1394 return -EINVAL;
1395 }
1396
1397 switch (type) {
1398 case OVS_NSH_KEY_ATTR_BASE: {
1399 const struct ovs_nsh_key_base *base = nla_data(a);
1400
1401 has_base = true;
1402 mdtype = base->mdtype;
1403 SW_FLOW_KEY_PUT(match, nsh.base.flags,
1404 base->flags, is_mask);
1405 SW_FLOW_KEY_PUT(match, nsh.base.ttl,
1406 base->ttl, is_mask);
1407 SW_FLOW_KEY_PUT(match, nsh.base.mdtype,
1408 base->mdtype, is_mask);
1409 SW_FLOW_KEY_PUT(match, nsh.base.np,
1410 base->np, is_mask);
1411 SW_FLOW_KEY_PUT(match, nsh.base.path_hdr,
1412 base->path_hdr, is_mask);
1413 break;
1414 }
1415 case OVS_NSH_KEY_ATTR_MD1: {
1416 const struct ovs_nsh_key_md1 *md1 = nla_data(a);
1417
1418 has_md1 = true;
1419 for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++)
1420 SW_FLOW_KEY_PUT(match, nsh.context[i],
1421 md1->context[i], is_mask);
1422 break;
1423 }
1424 case OVS_NSH_KEY_ATTR_MD2:
1425 if (!is_push_nsh) /* Not supported MD type 2 yet */
1426 return -ENOTSUPP;
1427
1428 has_md2 = true;
1429 mdlen = nla_len(a);
1430 if (mdlen > NSH_CTX_HDRS_MAX_LEN || mdlen <= 0) {
1431 OVS_NLERR(
1432 log,
1433 "Invalid MD length %d for MD type %d",
1434 mdlen,
1435 mdtype
1436 );
1437 return -EINVAL;
1438 }
1439 break;
1440 default:
1441 OVS_NLERR(log, "Unknown nsh attribute %d",
1442 type);
1443 return -EINVAL;
1444 }
1445 }
1446
1447 if (rem > 0) {
1448 OVS_NLERR(log, "nsh attribute has %d unknown bytes.", rem);
1449 return -EINVAL;
1450 }
1451
1452 if (has_md1 && has_md2) {
1453 OVS_NLERR(
1454 1,
1455 "invalid nsh attribute: md1 and md2 are exclusive."
1456 );
1457 return -EINVAL;
1458 }
1459
1460 if (!is_mask) {
1461 if ((has_md1 && mdtype != NSH_M_TYPE1) ||
1462 (has_md2 && mdtype != NSH_M_TYPE2)) {
1463 OVS_NLERR(1, "nsh attribute has unmatched MD type %d.",
1464 mdtype);
1465 return -EINVAL;
1466 }
1467
1468 if (is_push_nsh &&
1469 (!has_base || (!has_md1 && !has_md2))) {
1470 OVS_NLERR(
1471 1,
1472 "push_nsh: missing base or metadata attributes"
1473 );
1474 return -EINVAL;
1475 }
1476 }
1477
1478 return 0;
1479}
1480
1230static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, 1481static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
1231 u64 attrs, const struct nlattr **a, 1482 u64 attrs, const struct nlattr **a,
1232 bool is_mask, bool log) 1483 bool is_mask, bool log)
@@ -1354,6 +1605,13 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
1354 attrs &= ~(1 << OVS_KEY_ATTR_ARP); 1605 attrs &= ~(1 << OVS_KEY_ATTR_ARP);
1355 } 1606 }
1356 1607
1608 if (attrs & (1 << OVS_KEY_ATTR_NSH)) {
1609 if (nsh_key_put_from_nlattr(a[OVS_KEY_ATTR_NSH], match,
1610 is_mask, false, log) < 0)
1611 return -EINVAL;
1612 attrs &= ~(1 << OVS_KEY_ATTR_NSH);
1613 }
1614
1357 if (attrs & (1 << OVS_KEY_ATTR_MPLS)) { 1615 if (attrs & (1 << OVS_KEY_ATTR_MPLS)) {
1358 const struct ovs_key_mpls *mpls_key; 1616 const struct ovs_key_mpls *mpls_key;
1359 1617
@@ -1670,6 +1928,34 @@ static int ovs_nla_put_vlan(struct sk_buff *skb, const struct vlan_head *vh,
1670 return 0; 1928 return 0;
1671} 1929}
1672 1930
1931static int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask,
1932 struct sk_buff *skb)
1933{
1934 struct nlattr *start;
1935
1936 start = nla_nest_start(skb, OVS_KEY_ATTR_NSH);
1937 if (!start)
1938 return -EMSGSIZE;
1939
1940 if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(nsh->base), &nsh->base))
1941 goto nla_put_failure;
1942
1943 if (is_mask || nsh->base.mdtype == NSH_M_TYPE1) {
1944 if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1,
1945 sizeof(nsh->context), nsh->context))
1946 goto nla_put_failure;
1947 }
1948
1949 /* Don't support MD type 2 yet */
1950
1951 nla_nest_end(skb, start);
1952
1953 return 0;
1954
1955nla_put_failure:
1956 return -EMSGSIZE;
1957}
1958
1673static int __ovs_nla_put_key(const struct sw_flow_key *swkey, 1959static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
1674 const struct sw_flow_key *output, bool is_mask, 1960 const struct sw_flow_key *output, bool is_mask,
1675 struct sk_buff *skb) 1961 struct sk_buff *skb)
@@ -1798,6 +2084,9 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
1798 ipv6_key->ipv6_tclass = output->ip.tos; 2084 ipv6_key->ipv6_tclass = output->ip.tos;
1799 ipv6_key->ipv6_hlimit = output->ip.ttl; 2085 ipv6_key->ipv6_hlimit = output->ip.ttl;
1800 ipv6_key->ipv6_frag = output->ip.frag; 2086 ipv6_key->ipv6_frag = output->ip.frag;
2087 } else if (swkey->eth.type == htons(ETH_P_NSH)) {
2088 if (nsh_key_to_nlattr(&output->nsh, is_mask, skb))
2089 goto nla_put_failure;
1801 } else if (swkey->eth.type == htons(ETH_P_ARP) || 2090 } else if (swkey->eth.type == htons(ETH_P_ARP) ||
1802 swkey->eth.type == htons(ETH_P_RARP)) { 2091 swkey->eth.type == htons(ETH_P_RARP)) {
1803 struct ovs_key_arp *arp_key; 2092 struct ovs_key_arp *arp_key;
@@ -2292,6 +2581,19 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
2292 return err; 2581 return err;
2293} 2582}
2294 2583
2584static bool validate_nsh(const struct nlattr *attr, bool is_mask,
2585 bool is_push_nsh, bool log)
2586{
2587 struct sw_flow_match match;
2588 struct sw_flow_key key;
2589 int ret = 0;
2590
2591 ovs_match_init(&match, &key, true, NULL);
2592 ret = nsh_key_put_from_nlattr(attr, &match, is_mask,
2593 is_push_nsh, log);
2594 return !ret;
2595}
2596
2295/* Return false if there are any non-masked bits set. 2597/* Return false if there are any non-masked bits set.
2296 * Mask follows data immediately, before any netlink padding. 2598 * Mask follows data immediately, before any netlink padding.
2297 */ 2599 */
@@ -2434,6 +2736,13 @@ static int validate_set(const struct nlattr *a,
2434 2736
2435 break; 2737 break;
2436 2738
2739 case OVS_KEY_ATTR_NSH:
2740 if (eth_type != htons(ETH_P_NSH))
2741 return -EINVAL;
2742 if (!validate_nsh(nla_data(a), masked, false, log))
2743 return -EINVAL;
2744 break;
2745
2437 default: 2746 default:
2438 return -EINVAL; 2747 return -EINVAL;
2439 } 2748 }
@@ -2533,6 +2842,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
2533 [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc), 2842 [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
2534 [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth), 2843 [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
2535 [OVS_ACTION_ATTR_POP_ETH] = 0, 2844 [OVS_ACTION_ATTR_POP_ETH] = 0,
2845 [OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
2846 [OVS_ACTION_ATTR_POP_NSH] = 0,
2536 }; 2847 };
2537 const struct ovs_action_push_vlan *vlan; 2848 const struct ovs_action_push_vlan *vlan;
2538 int type = nla_type(a); 2849 int type = nla_type(a);
@@ -2690,6 +3001,34 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
2690 mac_proto = MAC_PROTO_ETHERNET; 3001 mac_proto = MAC_PROTO_ETHERNET;
2691 break; 3002 break;
2692 3003
3004 case OVS_ACTION_ATTR_PUSH_NSH:
3005 if (mac_proto != MAC_PROTO_ETHERNET) {
3006 u8 next_proto;
3007
3008 next_proto = tun_p_from_eth_p(eth_type);
3009 if (!next_proto)
3010 return -EINVAL;
3011 }
3012 mac_proto = MAC_PROTO_NONE;
3013 if (!validate_nsh(nla_data(a), false, true, true))
3014 return -EINVAL;
3015 break;
3016
3017 case OVS_ACTION_ATTR_POP_NSH: {
3018 __be16 inner_proto;
3019
3020 if (eth_type != htons(ETH_P_NSH))
3021 return -EINVAL;
3022 inner_proto = tun_p_to_eth_p(key->nsh.base.np);
3023 if (!inner_proto)
3024 return -EINVAL;
3025 if (key->nsh.base.np == TUN_P_ETHERNET)
3026 mac_proto = MAC_PROTO_ETHERNET;
3027 else
3028 mac_proto = MAC_PROTO_NONE;
3029 break;
3030 }
3031
2693 default: 3032 default:
2694 OVS_NLERR(log, "Unknown Action type %d", type); 3033 OVS_NLERR(log, "Unknown Action type %d", type);
2695 return -EINVAL; 3034 return -EINVAL;
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h
index 929c665ac3aa..6657606b2b47 100644
--- a/net/openvswitch/flow_netlink.h
+++ b/net/openvswitch/flow_netlink.h
@@ -79,4 +79,9 @@ int ovs_nla_put_actions(const struct nlattr *attr,
79void ovs_nla_free_flow_actions(struct sw_flow_actions *); 79void ovs_nla_free_flow_actions(struct sw_flow_actions *);
80void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *); 80void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *);
81 81
82int nsh_key_from_nlattr(const struct nlattr *attr, struct ovs_key_nsh *nsh,
83 struct ovs_key_nsh *nsh_mask);
84int nsh_hdr_from_nlattr(const struct nlattr *attr, struct nshhdr *nh,
85 size_t size);
86
82#endif /* flow_netlink.h */ 87#endif /* flow_netlink.h */