These actions will allow L2->L3 and L3->L2 switching, and are supposed to be added to flows installed in the datapath transparently by ovs-vswitchd.
Signed-off-by: Lorand Jakab <loja...@cisco.com> --- include/linux/openvswitch.h | 12 +++++++++ lib/odp-execute.c | 12 +++++++++ lib/odp-util.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ lib/odp-util.h | 6 +++++ lib/packets.c | 25 +++++++++++++++++++ lib/packets.h | 4 +++ 6 files changed, 120 insertions(+) diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index b429201..c36589f 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -519,6 +519,16 @@ struct ovs_action_push_vlan { }; /** + * struct ovs_action_push_eth - %OVS_ACTION_ATTR_PUSH_ETH action argument. + * @addresses: Source and destination MAC addresses. + * @eth_type: Ethernet type + */ +struct ovs_action_push_eth { + struct ovs_key_ethernet addresses; + __be16 eth_type; +}; + +/** * enum ovs_action_attr - Action types. * * @OVS_ACTION_ATTR_OUTPUT: Output packet to port. @@ -557,6 +567,8 @@ enum ovs_action_attr { OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */ OVS_ACTION_ATTR_PUSH_MPLS, /* struct ovs_action_push_mpls. */ OVS_ACTION_ATTR_POP_MPLS, /* __be16 ethertype. */ + OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */ + OVS_ACTION_ATTR_POP_ETH, /* No argument. */ __OVS_ACTION_ATTR_MAX }; diff --git a/lib/odp-execute.c b/lib/odp-execute.c index af3370d..e6ef770 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -207,6 +207,18 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key, break; } + case OVS_ACTION_ATTR_PUSH_ETH: { + const struct ovs_action_push_eth *eth = nl_attr_get(a); + push_eth(packet, eth->addresses.eth_dst, eth->addresses.eth_src, + eth->eth_type); + break; + } + + case OVS_ACTION_ATTR_POP_ETH: { + pop_eth(packet); + break; + } + case OVS_ACTION_ATTR_PUSH_VLAN: { const struct ovs_action_push_vlan *vlan = nl_attr_get(a); eth_push_vlan(packet, vlan->vlan_tci); diff --git a/lib/odp-util.c b/lib/odp-util.c index e20a0ba..d584d3f 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -74,6 +74,8 @@ odp_action_len(uint16_t type) switch ((enum ovs_action_attr) type) { case OVS_ACTION_ATTR_OUTPUT: return sizeof(uint32_t); case OVS_ACTION_ATTR_USERSPACE: return -2; + case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth); + case OVS_ACTION_ATTR_POP_ETH: return 0; case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan); case OVS_ACTION_ATTR_POP_VLAN: return 0; case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls); @@ -374,6 +376,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a) { int expected_len; enum ovs_action_attr type = nl_attr_type(a); + const struct ovs_action_push_eth *eth; const struct ovs_action_push_vlan *vlan; expected_len = odp_action_len(nl_attr_type(a)); @@ -396,6 +399,17 @@ format_odp_action(struct ds *ds, const struct nlattr *a) format_odp_key_attr(nl_attr_get(a), NULL, NULL, ds, true); ds_put_cstr(ds, ")"); break; + case OVS_ACTION_ATTR_PUSH_ETH: + eth = nl_attr_get(a); + 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), + ntohs(eth->eth_type)); + break; + case OVS_ACTION_ATTR_POP_ETH: + ds_put_cstr(ds, "pop_eth"); + break; case OVS_ACTION_ATTR_PUSH_VLAN: vlan = nl_attr_get(a); ds_put_cstr(ds, "push_vlan("); @@ -605,6 +619,31 @@ parse_odp_action(const char *s, const struct simap *port_names, } { + struct ovs_action_push_eth push; + int eth_type = 0; + int n = -1; + + if (sscanf(s, "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, &n) > 0 && n > 0) { + + push.eth_type = htons(eth_type); + + nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_ETH, + &push, sizeof push); + + return n; + } + } + + if (!strncmp(s, "pop_eth", 7)) { + nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_ETH); + return 7; + } + + { struct ovs_action_push_vlan push; int tpid = ETH_TYPE_VLAN; int vid, pcp; @@ -3332,6 +3371,28 @@ 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 uint8_t eth_src[ETH_ADDR_LEN], + const uint8_t eth_dst[ETH_ADDR_LEN], + const ovs_be16 eth_type) +{ + struct ovs_action_push_eth eth; + + memcpy(eth.addresses.eth_src, eth_src, ETH_ADDR_LEN); + memcpy(eth.addresses.eth_dst, eth_dst, ETH_ADDR_LEN); + 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 821b2c4..6a7a35c 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -26,6 +26,7 @@ #include "hmap.h" #include "openflow/openflow.h" #include "util.h" +#include "packets.h" struct ds; struct flow; @@ -226,6 +227,11 @@ BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 16); size_t odp_put_userspace_action(uint32_t pid, const void *userdata, size_t userdata_size, struct ofpbuf *odp_actions); +void odp_put_pop_eth_action(struct ofpbuf *odp_actions); +void odp_put_push_eth_action(struct ofpbuf *odp_actions, + const uint8_t eth_src[ETH_ADDR_LEN], + const uint8_t eth_dst[ETH_ADDR_LEN], + const ovs_be16 eth_type); void odp_put_tunnel_action(const struct flow_tnl *tunnel, struct ofpbuf *odp_actions); void odp_put_pkt_mark_action(const uint32_t pkt_mark, diff --git a/lib/packets.c b/lib/packets.c index dc1970a..a2206b7 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -218,6 +218,31 @@ eth_pop_vlan(struct ofpbuf *packet) } } +/* Push Ethernet header onto 'packet' assuming it is layer 3 */ +void +push_eth(struct ofpbuf *packet, const uint8_t dst[ETH_ADDR_LEN], + const uint8_t src[ETH_ADDR_LEN], ovs_be16 type) +{ + struct eth_header *eh = ofpbuf_push_uninit(packet, ETH_HEADER_LEN); + + memcpy(eh->eth_dst, dst, ETH_ADDR_LEN); + memcpy(eh->eth_src, src, ETH_ADDR_LEN); + eh->eth_type = type; + packet->l2 = packet->data; +} + +/* Removes Ethernet header, including all VLAN and MPLS headers, from + * 'packet'. + * + * Previous to calling this funciton, 'packet->l3' must be set. */ +void +pop_eth(struct ofpbuf *packet) +{ + packet->size -= (char*)packet->l3 - (char*)packet->l2; + packet->data = packet->l3; + packet->l2 = NULL; +} + /* Set ethertype of the packet. */ void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type) diff --git a/lib/packets.h b/lib/packets.h index f4f00ce..a6defe5 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -152,6 +152,10 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], const uint8_t mask[ETH_ADDR_LEN], uint8_t dst[ETH_ADDR_LEN]); +void push_eth(struct ofpbuf *packet, const uint8_t dst[ETH_ADDR_LEN], + const uint8_t src[ETH_ADDR_LEN], ovs_be16 type); +void pop_eth(struct ofpbuf *packet); + void set_mpls_lse(struct ofpbuf *, ovs_be32 label); void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse); void pop_mpls(struct ofpbuf *, ovs_be16 ethtype); -- 1.8.3.4 (Apple Git-47) _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev