Network Service Header is pushed to/stripped from packets with the data path flow actions push_nsh and pop_nsh.
Signed-off-by: Johnson Li <johnson...@intel.com> diff --git a/datapath/actions.c b/datapath/actions.c index dcf8591..69f5d2a 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -29,6 +29,7 @@ #include <linux/in6.h> #include <linux/if_arp.h> #include <linux/if_vlan.h> +#include <linux/if_ether.h> #include <net/dst.h> #include <net/ip.h> @@ -37,6 +38,7 @@ #include <net/dsfield.h> #include <net/mpls.h> #include <net/sctp/checksum.h> +#include <net/nsh.h> #include "datapath.h" #include "conntrack.h" @@ -252,6 +254,64 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); } +static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) +{ + struct nsh_hdr *nsh_hdr = NULL; + u16 length = 0; + + nsh_hdr = (struct nsh_hdr *)(skb->data); + length = nsh_hdr->base.length << 2; + + switch (nsh_hdr->base.next_proto) { + case NSH_P_IPV4: + skb->protocol = htons(ETH_P_IP); + key->eth.type = htons(ETH_P_IP); + break; + case NSH_P_IPV6: + skb->protocol = htons(ETH_P_IPV6); + key->eth.type = htons(ETH_P_IPV6); + break; + case NSH_P_ETHERNET: + skb->protocol = htons(ETH_P_TEB); + break; + default: + return -EINVAL; + } + + __skb_pull(skb, length); + skb_reset_mac_header(skb); + skb_reset_mac_len(skb); + + memset(&key->nsh, 0, sizeof(key->nsh)); + + return 0; +} + +static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, + const struct ovs_action_push_nsh *nsh) +{ + if (nsh->len > 0 && nsh->len <= 256) { + struct nsh_hdr *nsh_hdr = NULL; + + if (skb_cow_head(skb, nsh->len) < 0) + return -ENOMEM; + + skb_push(skb, nsh->len); + nsh_hdr = (struct nsh_hdr *)(skb->data); + memcpy(nsh_hdr, nsh->header, nsh->len); + + if (!skb->inner_protocol) + skb_set_inner_protocol(skb, skb->protocol); + + skb->protocol = htons(ETH_P_NSH); /* 0x894F */ + key->eth.type = htons(ETH_P_NSH); + } else { + return -EINVAL; + } + + return 0; +} + /* 'src' is already properly masked. */ static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) { @@ -1079,6 +1139,14 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, err = pop_vlan(skb, key); break; + case OVS_ACTION_ATTR_PUSH_NSH: + err = push_nsh(skb, key, nla_data(a)); + break; + + case OVS_ACTION_ATTR_POP_NSH: + err = pop_nsh(skb, key); + break; + case OVS_ACTION_ATTR_RECIRC: err = execute_recirc(dp, skb, key, a, rem); if (nla_is_last(a, rem)) { diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c index 15685c7..4e0aed2 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -2375,6 +2375,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash), [OVS_ACTION_ATTR_CT] = (u32)-1, + [OVS_ACTION_ATTR_PUSH_NSH] = sizeof(struct ovs_action_push_nsh), + [OVS_ACTION_ATTR_POP_NSH] = 0, }; const struct ovs_action_push_vlan *vlan; int type = nla_type(a); @@ -2427,6 +2429,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, vlan_tci = vlan->vlan_tci; break; + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: + break; + case OVS_ACTION_ATTR_RECIRC: break; diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 6cde92a..b6b6e47 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -646,6 +646,17 @@ struct ovs_action_push_vlan { __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */ }; +/** + * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument. + * @len: length of NSH header. Differs since different metadata type. + * @header: RAW value for the NSH header. + */ +#define NSH_HEADER_LEN_MAX 256 +struct ovs_action_push_nsh { + uint16_t len; + uint8_t header[NSH_HEADER_LEN_MAX]; /* NSH header */ +}; + /* Data path hash algorithm for computing Datapath hash. * * The algorithm type only specifies the fields in a flow @@ -788,6 +799,8 @@ enum ovs_nat_attr { * is no MPLS label stack, as determined by ethertype, no action is taken. * @OVS_ACTION_ATTR_CT: Track the connection. Populate the conntrack-related * entries in the flow key. + * @OVS_ACTION_ATTR_PUSH_NSH: Push a Network Service Header into the packets. + * @OVS_ACTION_ATTR_POP_NSH: Strip the Network Service Header from packets. * * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all * fields within a header are modifiable, e.g. the IPv4 protocol and fragment @@ -819,6 +832,8 @@ enum ovs_action_attr { * The data must be zero for the unmasked * bits. */ OVS_ACTION_ATTR_CT, /* Nested OVS_CT_ATTR_* . */ + OVS_ACTION_ATTR_PUSH_NSH, /* struct ovs_action_push_nsh. */ + OVS_ACTION_ATTR_POP_NSH, /* No argument. */ #ifndef __KERNEL__ OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 61a939a..b776f60 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -4160,6 +4160,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_HASH: case OVS_ACTION_ATTR_UNSPEC: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } diff --git a/lib/dpif.c b/lib/dpif.c index c4f24c7..d0bff3e 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1147,6 +1147,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 2de81dc..e37402c 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -505,6 +505,8 @@ requires_datapath_assistance(const struct nlattr *a) case OVS_ACTION_ATTR_HASH: case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_POP_MPLS: + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: return false; case OVS_ACTION_ATTR_UNSPEC: @@ -627,6 +629,10 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, } break; + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: + break; + case OVS_ACTION_ATTR_OUTPUT: case OVS_ACTION_ATTR_TUNNEL_PUSH: case OVS_ACTION_ATTR_TUNNEL_POP: diff --git a/lib/odp-util.c b/lib/odp-util.c index 8a2e521..f970e86 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -120,6 +120,8 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_SET_MASKED: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_SAMPLE: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_CT: return ATTR_LEN_VARIABLE; + case OVS_ACTION_ATTR_PUSH_NSH: return sizeof(struct ovs_action_push_nsh); + case OVS_ACTION_ATTR_POP_NSH: return 0; case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: @@ -849,6 +851,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a) case OVS_ACTION_ATTR_CT: format_odp_conntrack_action(ds, a); break; + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: + break; case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: default: diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c index 982e676..d63911d 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -1174,6 +1174,8 @@ dpif_sflow_read_actions(const struct flow *flow, dpif_sflow_pop_mpls_lse(sflow_actions); break; } + case OVS_ACTION_ATTR_PUSH_NSH: + case OVS_ACTION_ATTR_POP_NSH: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: -- 1.8.4.2 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev