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> --- datapath/linux/compat/include/linux/openvswitch.h | 12 +++++ lib/dpif-netdev.c | 2 + lib/dpif.c | 2 + lib/odp-execute.c | 19 +++++++ lib/odp-util.c | 61 +++++++++++++++++++++++ lib/odp-util.h | 6 +++ lib/packets.c | 25 ++++++++++ lib/packets.h | 4 ++ 8 files changed, 131 insertions(+) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index c8fa66e..e1b8d38 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -605,6 +605,16 @@ struct ovs_action_push_tnl { #endif /** + * 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. @@ -658,6 +668,8 @@ enum ovs_action_attr { OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */ 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_SET_MASKED, /* One nested OVS_KEY_ATTR_* including * data immediately followed by a mask. * The data must be zero for the unmasked diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 65df19b..3b9a862 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -3164,6 +3164,8 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt, VLOG_WARN("Packet dropped. Max recirculation depth exceeded."); break; + case OVS_ACTION_ATTR_PUSH_ETH: + case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_PUSH_MPLS: diff --git a/lib/dpif.c b/lib/dpif.c index d179d8a..086f0ba 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1044,6 +1044,8 @@ dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt, } case OVS_ACTION_ATTR_HASH: + case OVS_ACTION_ATTR_PUSH_ETH: + case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_PUSH_VLAN: case OVS_ACTION_ATTR_POP_VLAN: case OVS_ACTION_ATTR_PUSH_MPLS: diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 720d24e..ccc2566 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -471,6 +471,25 @@ odp_execute_actions(void *dp, struct dpif_packet **packets, int cnt, bool steal, break; } + case OVS_ACTION_ATTR_PUSH_ETH: { + const struct ovs_action_push_eth *eth = nl_attr_get(a); + + for (i = 0; i < cnt; i++) { + struct ofpbuf *ofp = &packets[i]->ofpbuf; + + push_eth(ofp, eth->addresses.eth_dst, eth->addresses.eth_src, + eth->eth_type); + } + break; + } + + case OVS_ACTION_ATTR_POP_ETH: { + for (i = 0; i < cnt; i++) { + pop_eth(&packets[i]->ofpbuf); + } + break; + } + case OVS_ACTION_ATTR_PUSH_VLAN: { const struct ovs_action_push_vlan *vlan = nl_attr_get(a); diff --git a/lib/odp-util.c b/lib/odp-util.c index 633919a..7be7a27 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -79,6 +79,8 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_TUNNEL_PUSH: return -2; case OVS_ACTION_ATTR_TUNNEL_POP: 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); @@ -598,6 +600,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; size_t size; @@ -655,6 +658,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("); @@ -1046,6 +1060,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 (ovs_scan(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)) { + + 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; @@ -3780,6 +3819,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 00dbf7b..0bbc347 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -27,6 +27,7 @@ #include "odp-netlink.h" #include "openflow/openflow.h" #include "util.h" +#include "packets.h" struct ds; struct nlattr; @@ -251,6 +252,11 @@ size_t odp_put_userspace_action(uint32_t pid, const void *userdata, size_t userdata_size, odp_port_t tunnel_out_port, 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); diff --git a/lib/packets.c b/lib/packets.c index af99e3b..ca56ff6 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -207,6 +207,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; + + eh = ofpbuf_resize_l2(packet, ETH_HEADER_LEN); + memcpy(eh->eth_dst, dst, ETH_ADDR_LEN); + memcpy(eh->eth_src, src, ETH_ADDR_LEN); + eh->eth_type = type; +} + +/* Removes Ethernet header, including all VLAN and MPLS headers, from 'packet'. + * + * Previous to calling this function, 'ofpbuf_l3(packet)' must not be NULL */ +void +pop_eth(struct ofpbuf *packet) +{ + ovs_assert(ofpbuf_l3(packet) != NULL); + + ofpbuf_resize_l2_5(packet, -packet->l3_ofs); + ofpbuf_set_l2_5(packet, NULL); +} + /* Set ethertype of the packet. */ static void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type) diff --git a/lib/packets.h b/lib/packets.h index 65d2274..1435af5 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -196,6 +196,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.9.3 (Apple Git-50) _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev