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 | 16 ++++++++++-- lib/dpif-netdev.c | 2 ++ lib/dpif.c | 2 ++ lib/odp-execute.c | 12 +++++++++ lib/odp-util.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ lib/odp-util.h | 6 +++++ lib/packets.c | 25 +++++++++++++++++++ lib/packets.h | 4 +++ 8 files changed, 126 insertions(+), 2 deletions(-) diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index d7f85ff..70ccbc9 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -565,6 +565,16 @@ struct ovs_action_hash { }; /** + * 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. @@ -602,10 +612,12 @@ enum ovs_action_attr { OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */ OVS_ACTION_ATTR_POP_VLAN, /* No argument. */ 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_RECIRC, /* u32 recirc_id. */ OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */ + OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */ + OVS_ACTION_ATTR_POP_ETH, /* No argument. */ + OVS_ACTION_ATTR_PUSH_MPLS = 61, /* struct ovs_action_push_mpls. */ + OVS_ACTION_ATTR_POP_MPLS = 62, /* __be16 ethertype. */ __OVS_ACTION_ATTR_MAX }; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index a255a96..40503a2 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2171,6 +2171,8 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, } 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 41b8eb7..d7cfc5c 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1126,6 +1126,8 @@ dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet, aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute); 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/odp-execute.c b/lib/odp-execute.c index 12ad679..64847a9 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -219,6 +219,18 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, } 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, htons(ETH_TYPE_VLAN), vlan->vlan_tci); diff --git a/lib/odp-util.c b/lib/odp-util.c index af464a0..a22ab01 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -75,6 +75,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); @@ -412,6 +414,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)); @@ -440,6 +443,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("); @@ -640,6 +654,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; @@ -3479,6 +3518,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 0dfbcca..64b16b0 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; @@ -233,6 +234,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 6244c3f..c1f7ade 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -206,6 +206,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 f294d84..1c36f7c 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -194,6 +194,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.5.2 (Apple Git-48) _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev