Message ID | 1486386290-94788-10-git-send-email-yi.y.yang@intel.com |
---|---|
State | Superseded |
Headers | show |
This patch has been superseded by patch series https://mail.openvswitch.org/pipermail/ovs-dev/2017-February/328391.html specifically patch https://mail.openvswitch.org/pipermail/ovs-dev/2017-February/328394.html Please exclude from review. BR, Jan > -----Original Message----- > From: ovs-dev-bounces@openvswitch.org [mailto:ovs-dev-bounces@openvswitch.org] On Behalf Of Yi Yang > Sent: Monday, 06 February, 2017 14:05 > To: dev@openvswitch.org > Cc: Simon Horman <simon.horman@netronome.com>; Jiri Benc <jbenc@redhat.com> > Subject: [ovs-dev] [PATCH v3 09/16] userspace: add support for pop_eth and push_eth actions > > 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 <lojakab@cisco.com> > Signed-off-by: Simon Horman <simon.horman@netronome.com> > Signed-off-by: Jiri Benc <jbenc@redhat.com> > Signed-off-by: Yi Yang <yi.y.yang@intel.com> > --- > lib/dpif-netdev.c | 2 ++ > lib/dpif.c | 2 ++ > lib/odp-execute.c | 18 ++++++++++ > lib/odp-util.c | 83 ++++++++++++++++++++++++++++++++++++++++++-- > lib/packets.c | 24 +++++++++++++ > lib/packets.h | 4 +++ > ofproto/ofproto-dpif-sflow.c | 7 ++++ > 7 files changed, 137 insertions(+), 3 deletions(-) > > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index 0be5db5..73927c4 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -4732,6 +4732,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, > case OVS_ACTION_ATTR_HASH: > case OVS_ACTION_ATTR_UNSPEC: > case OVS_ACTION_ATTR_TRUNC: > + case OVS_ACTION_ATTR_PUSH_ETH: > + case OVS_ACTION_ATTR_POP_ETH: > case OVS_ACTION_ATTR_CLONE: > case __OVS_ACTION_ATTR_MAX: > OVS_NOT_REACHED(); > diff --git a/lib/dpif.c b/lib/dpif.c > index 57aa3c6..1559ed4 100644 > --- a/lib/dpif.c > +++ b/lib/dpif.c > @@ -1182,6 +1182,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_, > case OVS_ACTION_ATTR_SET_MASKED: > case OVS_ACTION_ATTR_SAMPLE: > case OVS_ACTION_ATTR_TRUNC: > + case OVS_ACTION_ATTR_PUSH_ETH: > + case OVS_ACTION_ATTR_POP_ETH: > case OVS_ACTION_ATTR_CLONE: > case OVS_ACTION_ATTR_UNSPEC: > case __OVS_ACTION_ATTR_MAX: > diff --git a/lib/odp-execute.c b/lib/odp-execute.c > index 1f6812a..c0d6a20 100644 > --- a/lib/odp-execute.c > +++ b/lib/odp-execute.c > @@ -580,6 +580,8 @@ requires_datapath_assistance(const struct nlattr *a) > case OVS_ACTION_ATTR_PUSH_MPLS: > case OVS_ACTION_ATTR_POP_MPLS: > case OVS_ACTION_ATTR_TRUNC: > + case OVS_ACTION_ATTR_POP_ETH: > + case OVS_ACTION_ATTR_PUSH_ETH: > case OVS_ACTION_ATTR_CLONE: > return false; > > @@ -724,6 +726,22 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, > } > 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); > + } > + 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: > case OVS_ACTION_ATTR_TUNNEL_POP: > diff --git a/lib/odp-util.c b/lib/odp-util.c > index 4106738..36e611b 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -124,6 +124,8 @@ odp_action_len(uint16_t type) > case OVS_ACTION_ATTR_SET_MASKED: return ATTR_LEN_VARIABLE; > case OVS_ACTION_ATTR_SAMPLE: return ATTR_LEN_VARIABLE; > case OVS_ACTION_ATTR_CT: return ATTR_LEN_VARIABLE; > + 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_CLONE: return ATTR_LEN_VARIABLE; > > case OVS_ACTION_ATTR_UNSPEC: > @@ -850,6 +852,16 @@ 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: { > + 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")", > + ETH_ADDR_ARGS(eth->addresses.eth_src), > + ETH_ADDR_ARGS(eth->addresses.eth_dst)); > + break; > + } > + case OVS_ACTION_ATTR_POP_ETH: > + ds_put_cstr(ds, "pop_eth"); > + break; > case OVS_ACTION_ATTR_PUSH_VLAN: { > const struct ovs_action_push_vlan *vlan = nl_attr_get(a); > ds_put_cstr(ds, "push_vlan("); > @@ -1055,14 +1067,39 @@ 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 n1 = -1; > + > + if (ovs_scan(&s[n], "push_eth(src="ETH_ADDR_SCAN_FMT"," > + "dst="ETH_ADDR_SCAN_FMT")%n", > + ETH_ADDR_SCAN_ARGS(push.addresses.eth_src), > + ETH_ADDR_SCAN_ARGS(push.addresses.eth_dst), &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; > @@ -5360,6 +5397,26 @@ odp_put_userspace_action(uint32_t pid, > return userdata_ofs; > } > > +static void > +odp_put_pop_eth_action(struct ofpbuf *odp_actions) > +{ > + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH); > +} > + > +static void > +odp_put_push_eth_action(struct ofpbuf *odp_actions, > + const struct eth_addr *eth_src, > + const struct eth_addr *eth_dst) > +{ > + struct ovs_action_push_eth eth; > + > + eth.addresses.eth_src = *eth_src; > + eth.addresses.eth_dst = *eth_dst; > + > + 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) > @@ -5493,6 +5550,26 @@ commit_set_ether_addr_action(const struct flow *flow, struct flow *base_flow, > } > > static void > +commit_ether_action(const struct flow *flow, struct flow *base_flow, > + struct ofpbuf *odp_actions, struct flow_wildcards *wc, > + bool use_masked) > +{ > + if (flow->base_layer != base_flow->base_layer) { > + if (flow->base_layer == LAYER_2) { > + odp_put_push_eth_action(odp_actions, &flow->dl_src, &flow->dl_dst); > + base_flow->dl_src = flow->dl_src; > + base_flow->dl_dst = flow->dl_dst; > + } else { > + odp_put_pop_eth_action(odp_actions); > + } > + base_flow->base_layer = flow->base_layer; > + } > + > + commit_set_ether_addr_action(flow, base_flow, odp_actions, wc, > + use_masked); > +} > + > +static void > pop_vlan(struct flow *base, > struct ofpbuf *odp_actions, struct flow_wildcards *wc) > { > @@ -5953,7 +6030,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base, > enum slow_path_reason slow1, slow2; > bool mpls_done = false; > > - commit_set_ether_addr_action(flow, base, odp_actions, wc, use_masked); > + commit_ether_action(flow, base, odp_actions, wc, use_masked); > /* Make packet a non-MPLS packet before committing L3/4 actions, > * which would otherwise do nothing. */ > if (eth_type_mpls(base->dl_type) && !eth_type_mpls(flow->dl_type)) { > diff --git a/lib/packets.c b/lib/packets.c > index fa70df6..e440aaa 100644 > --- a/lib/packets.c > +++ b/lib/packets.c > @@ -225,6 +225,30 @@ 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) > +{ > + struct eth_header *eh; > + > + eh = dp_packet_resize_l2(packet, ETH_HEADER_LEN); > + eh->eth_dst = *dst; > + eh->eth_src = *src; > +} > + > +/* 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 dp_packet *packet) > +{ > + ovs_assert(dp_packet_l3(packet) != NULL); > + > + dp_packet_resize_l2_5(packet, -packet->l3_ofs); > + dp_packet_set_l2_5(packet, NULL); > +} > + > /* 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 c4d3799..bf2e7c2 100644 > --- a/lib/packets.h > +++ b/lib/packets.h > @@ -366,6 +366,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); > +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 520b8dd..beb4b1f 100644 > --- a/ofproto/ofproto-dpif-sflow.c > +++ b/ofproto/ofproto-dpif-sflow.c > @@ -1164,6 +1164,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_SAMPLE: > case OVS_ACTION_ATTR_CLONE: > case OVS_ACTION_ATTR_UNSPEC: > -- > 2.1.0 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 0be5db5..73927c4 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -4732,6 +4732,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_HASH: case OVS_ACTION_ATTR_UNSPEC: case OVS_ACTION_ATTR_TRUNC: + case OVS_ACTION_ATTR_PUSH_ETH: + case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_CLONE: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); diff --git a/lib/dpif.c b/lib/dpif.c index 57aa3c6..1559ed4 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1182,6 +1182,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_, case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_TRUNC: + case OVS_ACTION_ATTR_PUSH_ETH: + case OVS_ACTION_ATTR_POP_ETH: case OVS_ACTION_ATTR_CLONE: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 1f6812a..c0d6a20 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -580,6 +580,8 @@ requires_datapath_assistance(const struct nlattr *a) case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_TRUNC: + case OVS_ACTION_ATTR_POP_ETH: + case OVS_ACTION_ATTR_PUSH_ETH: case OVS_ACTION_ATTR_CLONE: return false; @@ -724,6 +726,22 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal, } 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); + } + 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: case OVS_ACTION_ATTR_TUNNEL_POP: diff --git a/lib/odp-util.c b/lib/odp-util.c index 4106738..36e611b 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -124,6 +124,8 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_SET_MASKED: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_SAMPLE: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_CT: return ATTR_LEN_VARIABLE; + 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_CLONE: return ATTR_LEN_VARIABLE; case OVS_ACTION_ATTR_UNSPEC: @@ -850,6 +852,16 @@ 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: { + 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")", + ETH_ADDR_ARGS(eth->addresses.eth_src), + ETH_ADDR_ARGS(eth->addresses.eth_dst)); + break; + } + case OVS_ACTION_ATTR_POP_ETH: + ds_put_cstr(ds, "pop_eth"); + break; case OVS_ACTION_ATTR_PUSH_VLAN: { const struct ovs_action_push_vlan *vlan = nl_attr_get(a); ds_put_cstr(ds, "push_vlan("); @@ -1055,14 +1067,39 @@ 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 n1 = -1; + + if (ovs_scan(&s[n], "push_eth(src="ETH_ADDR_SCAN_FMT"," + "dst="ETH_ADDR_SCAN_FMT")%n", + ETH_ADDR_SCAN_ARGS(push.addresses.eth_src), + ETH_ADDR_SCAN_ARGS(push.addresses.eth_dst), &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; @@ -5360,6 +5397,26 @@ odp_put_userspace_action(uint32_t pid, return userdata_ofs; } +static void +odp_put_pop_eth_action(struct ofpbuf *odp_actions) +{ + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_ETH); +} + +static void +odp_put_push_eth_action(struct ofpbuf *odp_actions, + const struct eth_addr *eth_src, + const struct eth_addr *eth_dst) +{ + struct ovs_action_push_eth eth; + + eth.addresses.eth_src = *eth_src; + eth.addresses.eth_dst = *eth_dst; + + 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) @@ -5493,6 +5550,26 @@ commit_set_ether_addr_action(const struct flow *flow, struct flow *base_flow, } static void +commit_ether_action(const struct flow *flow, struct flow *base_flow, + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) +{ + if (flow->base_layer != base_flow->base_layer) { + if (flow->base_layer == LAYER_2) { + odp_put_push_eth_action(odp_actions, &flow->dl_src, &flow->dl_dst); + base_flow->dl_src = flow->dl_src; + base_flow->dl_dst = flow->dl_dst; + } else { + odp_put_pop_eth_action(odp_actions); + } + base_flow->base_layer = flow->base_layer; + } + + commit_set_ether_addr_action(flow, base_flow, odp_actions, wc, + use_masked); +} + +static void pop_vlan(struct flow *base, struct ofpbuf *odp_actions, struct flow_wildcards *wc) { @@ -5953,7 +6030,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base, enum slow_path_reason slow1, slow2; bool mpls_done = false; - commit_set_ether_addr_action(flow, base, odp_actions, wc, use_masked); + commit_ether_action(flow, base, odp_actions, wc, use_masked); /* Make packet a non-MPLS packet before committing L3/4 actions, * which would otherwise do nothing. */ if (eth_type_mpls(base->dl_type) && !eth_type_mpls(flow->dl_type)) { diff --git a/lib/packets.c b/lib/packets.c index fa70df6..e440aaa 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -225,6 +225,30 @@ 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) +{ + struct eth_header *eh; + + eh = dp_packet_resize_l2(packet, ETH_HEADER_LEN); + eh->eth_dst = *dst; + eh->eth_src = *src; +} + +/* 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 dp_packet *packet) +{ + ovs_assert(dp_packet_l3(packet) != NULL); + + dp_packet_resize_l2_5(packet, -packet->l3_ofs); + dp_packet_set_l2_5(packet, NULL); +} + /* 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 c4d3799..bf2e7c2 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -366,6 +366,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); +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 520b8dd..beb4b1f 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -1164,6 +1164,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_SAMPLE: case OVS_ACTION_ATTR_CLONE: case OVS_ACTION_ATTR_UNSPEC: