On Thu, Oct 16, 2014 at 11:38:20AM -0700, Pravin B Shelar wrote:
> Following patch adds support for userspace tunneling. Tunneling
> needs three more component first is routing table which is configured by
> caching kernel routes and second is ARP cache which build automatically
> by snooping arp. And third is tunnel protocol table which list all
> listening protocols which is populated by vswitchd as tunnel ports
> are added.
>
> Tunneling works as follows:
> On packet receive vswitchd check if this packet is targeted to tunnel
> port. If it is then vswitchd inserts tunnel pop action which pops
> header and sends packet to tunnel port.
> On packet xmit rather than generating Set tunnel action it generate
> tunnel push action which has tunnel header data. datapath can use
> tunnel-push action data to generate header for each packet and
> forward this packet to output port. Since tunnel-push action
> contains most of packet header it need to lookup routing table and
> arp table to build this action.
>
> Signed-off-by: Pravin B Shelar <[email protected]>
I think that struct ovs_action_push_tnl is meant to be userspace-only so
far. In openvswitch.h, should the struct definition itself be enclosed
in #ifndef __KERNEL__...#endif?
(But I find myself wondering whether we should have a userspace-only
extension mechanism for openvswitch.h.)
> +static int
> +push_tunnel_action(const struct dp_netdev *dp,
> + const struct nlattr *attr,
> + struct dpif_packet **packets, int cnt)
> +{
> + struct dp_netdev_port *tun_port;
> + struct ovs_action_push_tnl *data;
> +
> + data = (struct ovs_action_push_tnl *) nl_attr_get(attr);
The cast above shouldn't really be necessary, at least if you mark
'data' as const.
> +static void
> +dp_netdev_clone_pkt_batch(struct dpif_packet **tnl_pkt,
> + struct dpif_packet **packets, int cnt)
> +{
> + int i;
> +
> + for (i = 0; i < cnt; i++) {
> + struct dpif_packet *inner_pkt;
> +
> + inner_pkt = dpif_packet_clone(packets[i]);
> + tnl_pkt[i] = inner_pkt;
The lines above are a long way to write "tnl_pkt[i] =
dpif_packet_clone(packets[i]);".
> + }
> +}
> +
> static void
> dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
> const struct nlattr *a, bool may_steal)
> @@ -2816,6 +2862,60 @@ dp_execute_cb(void *aux_, struct dpif_packet
> **packets, int cnt,
> }
> break;
>
> + case OVS_ACTION_ATTR_TUNNEL_PUSH:
> + if (*depth < MAX_RECIRC_DEPTH) {
> + struct dpif_packet *tnl_pkt[NETDEV_MAX_RX_BATCH];
> + int err;
> +
> + if (!may_steal) {
> + dp_netdev_clone_pkt_batch(tnl_pkt, packets, cnt);
> + packets = tnl_pkt;
> + }
> +
> + err = push_tunnel_action(dp, a, packets, cnt);
> + if (err) {
> + dp_netdev_drop_packets(tnl_pkt, cnt, !may_steal);
> + break;
> + }
> +
> + (*depth)++;
> + dp_netdev_input(pmd, packets, cnt);
> + (*depth)--;
> + return;
> + }
> + break;
> +
> + case OVS_ACTION_ATTR_TUNNEL_POP:
> + if (*depth < MAX_RECIRC_DEPTH) {
> + odp_port_t portno = u32_to_odp(nl_attr_get_u32(a));
> +
> + p = dp_netdev_lookup_port(dp, portno);
> + if (p) {
> + struct dpif_packet *tnl_pkt[NETDEV_MAX_RX_BATCH];
> + int err;
> +
> + if (!may_steal) {
> + dp_netdev_clone_pkt_batch(tnl_pkt, packets, cnt);
> + packets = tnl_pkt;
> + }
> +
> + err = netdev_pop_header(p->netdev, packets, cnt);
> + if (!err) {
> +
> + for (i = 0; i < cnt; i++) {
> + packets[i]->md.in_port.odp_port = portno;
> + }
> +
> + (*depth)++;
> + dp_netdev_input(pmd, packets, cnt);
> + (*depth)--;
> + return;
> + }
> + dp_netdev_drop_packets(tnl_pkt, cnt, !may_steal);
The OVS_ACTION_ATTR_TUNNEL_POP case here handles the success case inside
an 'if' statement; the OVS_ACTION_ATTR_TUNNEL_PUSH handles the failure
case inside an 'if' statement. I think that either approach is fine but
I'd find the code more straightforward if a consistent approach were used.
We now have multiple cases of code that checks and increments the depth
and calls dp_netdev_input() and reduces the depth. I wonder whether we
could encapsulate that in a neat helper function, or just put it into
dp_netdev_input() itself.
We usually put the return type and function name on separate lines in
userspace:
> +bool dpif_support_tnl_push_pop(const struct dpif *dpif)
> +{
> + return !strcmp(dpif->dpif_class->type, "netdev") ||
> + !strcmp(dpif->dpif_class->type, "dummy");
> +}
We usually give the header guard the same name as the header file (this
is in a file named gre.h):
> +#ifndef NETDEV_GRE_H
> +#define NETDEV_GRE_H 1
> +
This header file doesn't require most of the headers below:
> +#include <stddef.h>
> +#include <stdint.h>
> +#include "list.h"
> +#include "packets.h"
> +#include "util.h"
> +#include "netdev-dpdk.h"
We don't usually add extern "C" unless someone asks for them:
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/* GRE protocol header */
> +struct gre_base_hdr {
> + ovs_be16 flags;
> + ovs_be16 protocol;
This __attribute__ is going to cause trouble on MSVC:
> +}__attribute__((aligned(4)));
> +
> +#define GRE_HEADER_SECTION 4
> +
It's pretty unusual for us to put htons() into value definitions:
> +#define GRE_CSUM htons(0x8000)
> +#define GRE_ROUTING htons(0x4000)
> +#define GRE_KEY htons(0x2000)
> +#define GRE_SEQ htons(0x1000)
> +#define GRE_STRICT htons(0x0800)
> +#define GRE_REC htons(0x0700)
> +#define GRE_FLAGS htons(0x00F8)
> +#define GRE_VERSION htons(0x0007)
Did you consider putting the GRE definitions into packets.h?
I need to restart reading the code at netdev-vport.c.
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev