From: Jan Scheurich <jan.scheur...@ericsson.com> Add support for actions push_eth and pop_eth to the netdev datapath and the supporting libraries. This patch relies on the support for these actions in the kernel datapath to be present.
Signed-off-by: Lorand Jakab <loja...@cisco.com> Signed-off-by: Simon Horman <simon.hor...@netronome.com> Signed-off-by: Jiri Benc <jb...@redhat.com> Signed-off-by: Yi Yang <yi.y.y...@intel.com> Signed-off-by: Jean Tourrilhes <j...@labs.hpe.com> Signed-off-by: Jan Scheurich <jan.scheur...@ericsson.com> Co-authored-by: Zoltan Balogh <zoltan.bal...@ericsson.com> --- datapath/linux/compat/include/linux/openvswitch.h | 6 ++- lib/odp-execute.c | 17 +++++- lib/odp-util.c | 64 +++++++++++++++++++++-- lib/odp-util.h | 7 +++ lib/packets.c | 41 +++++++++++++++ lib/packets.h | 4 ++ ofproto/ofproto-dpif-sflow.c | 14 ++--- 7 files changed, 138 insertions(+), 15 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index f2ef0c1..ad979eb 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -747,6 +747,9 @@ enum ovs_ct_attr { */ struct ovs_action_push_eth { struct ovs_key_ethernet addresses; +#ifndef __KERNEL__ + __be16 eth_type; +#endif }; /** @@ -823,8 +826,7 @@ enum ovs_nat_attr { * entries in the flow key. * @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet header onto the * packet. - * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the - * packet. + * @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the packet. * * 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 diff --git a/lib/odp-execute.c b/lib/odp-execute.c index c4563b1..8e090c8 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -732,6 +732,21 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, case OVS_ACTION_ATTR_METER: /* Not implemented yet. */ break; + case OVS_ACTION_ATTR_PUSH_ETH: { + const struct ovs_action_push_eth *eth = nl_attr_get(a); + + DP_PACKET_BATCH_FOR_EACH (packet, batch) { + push_eth(packet, ð->addresses.eth_dst, + ð->addresses.eth_src, eth->eth_type); + } + break; + } + + case OVS_ACTION_ATTR_POP_ETH: + DP_PACKET_BATCH_FOR_EACH (packet, batch) { + pop_eth(packet); + } + break; case OVS_ACTION_ATTR_OUTPUT: case OVS_ACTION_ATTR_TUNNEL_PUSH: @@ -739,8 +754,6 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, case OVS_ACTION_ATTR_USERSPACE: case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_CT: - case OVS_ACTION_ATTR_PUSH_ETH: - case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); diff --git a/lib/odp-util.c b/lib/odp-util.c index 8747778..f137044 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -865,9 +865,11 @@ format_odp_action(struct ds *ds, const struct nlattr *a) break; case OVS_ACTION_ATTR_PUSH_ETH: { const struct ovs_action_push_eth *eth = nl_attr_get(a); - ds_put_format(ds, "push_eth(src="ETH_ADDR_FMT",dst="ETH_ADDR_FMT")", + ds_put_format(ds, "push_eth(src="ETH_ADDR_FMT",dst="ETH_ADDR_FMT + ",type=0x%04"PRIx16")", ETH_ADDR_ARGS(eth->addresses.eth_src), - ETH_ADDR_ARGS(eth->addresses.eth_dst)); + ETH_ADDR_ARGS(eth->addresses.eth_dst), + ntohs(eth->eth_type)); break; } case OVS_ACTION_ATTR_POP_ETH: @@ -1078,14 +1080,41 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions) odp_put_userspace_action(pid, user_data, user_data_size, tunnel_out_port, include_actions, actions); res = n + n1; + goto out; } else if (s[n] == ')') { odp_put_userspace_action(pid, user_data, user_data_size, ODPP_NONE, include_actions, actions); res = n + 1; - } else { - res = -EINVAL; + goto out; + } + } + + { + struct ovs_action_push_eth push; + int eth_type = 0; + int n1 = -1; + + if (ovs_scan(&s[n], "push_eth(src="ETH_ADDR_SCAN_FMT"," + "dst="ETH_ADDR_SCAN_FMT",type=%i)%n", + ETH_ADDR_SCAN_ARGS(push.addresses.eth_src), + ETH_ADDR_SCAN_ARGS(push.addresses.eth_dst), + ð_type, &n1)) { + + nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH, + &push, sizeof push); + + res = n + n1; + goto out; } } + + if (!strncmp(&s[n], "pop_eth", 7)) { + nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH); + res = 7; + goto out; + } + + res = -EINVAL; out: ofpbuf_uninit(&buf); return res; @@ -5564,6 +5593,33 @@ odp_put_userspace_action(uint32_t pid, } void +odp_put_pop_eth_action(struct ofpbuf *odp_actions) +{ + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH); +} + +void +odp_put_push_eth_action(struct ofpbuf *odp_actions, + const struct eth_addr *eth_src, + const struct eth_addr *eth_dst, + const ovs_be16 eth_type) +{ + struct ovs_action_push_eth eth; + + memset(ð, 0, sizeof eth); + if (eth_src) { + eth.addresses.eth_src = *eth_src; + } + if (eth_dst) { + eth.addresses.eth_dst = *eth_dst; + } + eth.eth_type = eth_type; + + nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_ETH, + ð, sizeof eth); +} + +void odp_put_tunnel_action(const struct flow_tnl *tunnel, struct ofpbuf *odp_actions) { diff --git a/lib/odp-util.h b/lib/odp-util.h index 66c194b..cb87c12 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -318,4 +318,11 @@ void odp_put_tunnel_action(const struct flow_tnl *tunnel, void odp_put_tnl_push_action(struct ofpbuf *odp_actions, struct ovs_action_push_tnl *data); + +void odp_put_pop_eth_action(struct ofpbuf *odp_actions); +void odp_put_push_eth_action(struct ofpbuf *odp_actions, + const struct eth_addr *eth_src, + const struct eth_addr *eth_dst, + const ovs_be16 eth_type); + #endif /* odp-util.h */ diff --git a/lib/packets.c b/lib/packets.c index 26781b0..3bf5e94 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -226,6 +226,47 @@ eth_pop_vlan(struct dp_packet *packet) } } +/* Push Ethernet header onto 'packet' assuming it is layer 3 */ +void +push_eth(struct dp_packet *packet, const struct eth_addr *dst, + const struct eth_addr *src, ovs_be16 type) +{ + struct eth_header *eh; + + ovs_assert(packet->packet_type != htonl(PT_ETH)); + eh = dp_packet_resize_l2(packet, ETH_HEADER_LEN); + eh->eth_dst = *dst; + eh->eth_src = *src; + eh->eth_type = type; + packet->packet_type = htonl(PT_ETH); +} + +/* Removes Ethernet header, including VLAN header, from 'packet'. + * + * Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */ +void +pop_eth(struct dp_packet *packet) +{ + char *l2_5 = dp_packet_l2_5(packet); + char *l3 = dp_packet_l3(packet); + ovs_be16 ethertype; + int increment; + + ovs_assert(packet->packet_type == htonl(PT_ETH)); + ovs_assert(l3 != NULL); + + if (l2_5) { + increment = packet->l2_5_ofs; + ethertype = *(ALIGNED_CAST(ovs_be16 *, (l2_5 - 2))); + } else { + increment = packet->l3_ofs; + ethertype = *(ALIGNED_CAST(ovs_be16 *, (l3 - 2))); + } + + dp_packet_resize_l2(packet, -increment); + packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, htons(ethertype)); +} + /* Set ethertype of the packet. */ static void set_ethertype(struct dp_packet *packet, ovs_be16 eth_type) diff --git a/lib/packets.h b/lib/packets.h index 092e7c5..3a8ac74 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -371,6 +371,10 @@ struct eth_header { }); BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header)); +void push_eth(struct dp_packet *packet, const struct eth_addr *dst, + const struct eth_addr *src, ovs_be16 type); +void pop_eth(struct dp_packet *packet); + #define LLC_DSAP_SNAP 0xaa #define LLC_SSAP_SNAP 0xaa #define LLC_CNTL_SNAP 3 diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c index 59fafa1..43483d7 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -1188,13 +1188,13 @@ dpif_sflow_read_actions(const struct flow *flow, dpif_sflow_pop_mpls_lse(sflow_actions); break; } - case OVS_ACTION_ATTR_PUSH_ETH: - case OVS_ACTION_ATTR_POP_ETH: - /* TODO: SFlow does not currently define a MAC-in-MAC - * encapsulation structure. We could use an extension - * structure to report this. - */ - break; + case OVS_ACTION_ATTR_PUSH_ETH: + case OVS_ACTION_ATTR_POP_ETH: + /* TODO: SFlow does not currently define a MAC-in-MAC + * encapsulation structure. We could use an extension + * structure to report this. + */ + break; case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_CLONE: case OVS_ACTION_ATTR_UNSPEC: -- 2.7.4 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev