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/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/include/linux/openvswitch.h b/include/linux/openvswitch.h index bf27dcb..78d403b 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -566,6 +566,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. @@ -607,6 +617,8 @@ enum ovs_action_attr { 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_MAX }; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index fce2650..c08d2dd 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2333,6 +2333,8 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt, } 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 2b6f36d..befe7c4 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1108,6 +1108,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 cb89e72..b5add78 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -260,6 +260,25 @@ odp_execute_actions__(void *dp, struct dpif_packet **packets, int cnt, 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 162d85a..bf64830 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; @@ -3535,6 +3574,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 4ce693c..d4169db 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -27,6 +27,7 @@ #include "hmap.h" #include "openflow/openflow.h" #include "util.h" +#include "packets.h" struct ds; struct nlattr; @@ -237,6 +238,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 c04e3bb..dad4554 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