On Fri, Oct 24, 2014 at 9:43 AM, Ben Pfaff <[email protected]> wrote:
> 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.)
>
I will give a shot. Let me know if you already have idea.
>> +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.
>
ok.
>> +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]);".
>
ok.
>
>> + }
>> +}
>> +
>> 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.
>
ok.
> 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");
>> +}
>
right.
> 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:
>
ok, I will use packed attribute.
>> +}__attribute__((aligned(4)));
>> +
>> +#define GRE_HEADER_SECTION 4
>> +
>
> It's pretty unusual for us to put htons() into value definitions:
ok I will fix it.
>> +#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?
>
ok, I will move gre and vxlan header definitions to packets.h.
> I need to restart reading the code at netdev-vport.c.
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev