diff options
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | lib/meta-flow.xml | 30 | ||||
-rw-r--r-- | lib/netdev-bsd.c | 1 | ||||
-rw-r--r-- | lib/netdev-dpdk.c | 1 | ||||
-rw-r--r-- | lib/netdev-dummy.c | 1 | ||||
-rw-r--r-- | lib/netdev-linux.c | 1 | ||||
-rw-r--r-- | lib/netdev-native-tnl.c | 23 | ||||
-rw-r--r-- | lib/netdev-provider.h | 6 | ||||
-rw-r--r-- | lib/netdev-vport.c | 107 | ||||
-rw-r--r-- | lib/netdev-vport.h | 1 | ||||
-rw-r--r-- | lib/netdev.c | 8 | ||||
-rw-r--r-- | lib/netdev.h | 29 | ||||
-rw-r--r-- | ofproto/ofproto-dpif-xlate.c | 35 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.c | 4 | ||||
-rw-r--r-- | ofproto/tunnel.c | 27 | ||||
-rw-r--r-- | tests/tunnel-push-pop-ipv6.at | 4 | ||||
-rw-r--r-- | tests/tunnel-push-pop.at | 4 | ||||
-rw-r--r-- | vswitchd/vswitch.xml | 94 |
18 files changed, 280 insertions, 102 deletions
@@ -59,11 +59,9 @@ Post-v2.7.0 * OVN services are no longer restarted automatically after upgrade. - Add --cleanup option to command 'ovs-appctl exit' (see ovs-vswitchd(8)). - L3 tunneling: - * Add "layer3" options for tunnel ports that support non-Ethernet (L3) - payload (GRE, VXLAN-GPE). + * Use new tunnel port option "packet_type" to configure L2 vs. L3. * New vxlan tunnel extension "gpe" to support VXLAN-GPE tunnels. - * Transparently pop and push Ethernet headers at transmit/reception - of packets to/from L3 tunnels. + * New support for non-Ethernet (L3) payloads in GRE and VXLAN-GPE. - The BFD detection multiplier is now user-configurable. - Add experimental support for hardware offloading * HW offloading is disabled by default. diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml index 856e1ba8c..634ab69e4 100644 --- a/lib/meta-flow.xml +++ b/lib/meta-flow.xml @@ -26,19 +26,27 @@ networking technology in use are called called <dfn>root fields</dfn>. Open vSwitch 2.7 and earlier considered Ethernet fields to be root fields, and this remains the default mode of operation for Open vSwitch bridges. - In this mode, when a packet is received from a non-Ethernet interfaces, - such as a layer-3 LISP or GRE tunnel, Open vSwitch force-fits it to this + When a packet is received from a non-Ethernet interfaces, such as a layer-3 + LISP tunnel, Open vSwitch 2.7 and earlier force-fit the packet to this Ethernet-centric point of view by pretending that an Ethernet header is present whose Ethernet type that indicates the packet's actual type (and whose source and destination addresses are all-zero). </p> <p> - Open vSwitch 2.8 and later supports the ``packet type-aware pipeline'' - concept introduced in OpenFlow 1.5. A bridge configured to be packet - type-aware can handle packets of multiple networking technologies, such as - Ethernet, IP, ARP, MPLS, or NSH in parallel. Such a bridge does not have - any root fields. + Open vSwitch 2.8 and later implement the ``packet type-aware pipeline'' + concept introduced in OpenFlow 1.5. Such a pipeline does not have any root + fields. Instead, a new metadata field, <ref field="packet_type"/>, + indicates the basic type of the packet, which can be Ethernet, IPv4, IPv6, + or another type. For backward compatibility, by default Open vSwitch 2.8 + imitates the behavior of Open vSwitch 2.7 and earlier. Later versions of + Open vSwitch may change the default, and in the meantime controllers can + turn off this legacy behavior, on a port-by-port basis, by setting + <code>options:packet_type</code> to <code>ptap</code> in the + <code>Interface</code> table. This is significant only for ports that can + handle non-Ethernet packets, which is currently just LISP, VXLAN-GPE, and + GRE tunnel ports. See <code>ovs-vwitchd.conf.db</code>(5) for more + information. </p> <p> @@ -332,14 +340,6 @@ tcp,tp_src=0x07c0/0xfff0 <dt><code>mplsm</code></dt> <dd><code>eth_type=0x8848</code></dd> </dl> - <p> - These shorthand notations continue to work in packet type-aware bridges. - The absence of a packet_type match implies - <code>packet_type=ethernet</code>, so that shorthands match on Ethernet - packets with the implied eth_type. Please note that the shorthand - <code>ip</code> does not match packets of packet_type (1,0x800) for IPv4. - </p> - <h2>Evolution of OpenFlow Fields</h2> diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index f863a189c..6cc83d347 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -1517,6 +1517,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off, \ GET_FEATURES, \ NULL, /* set_advertisement */ \ + NULL, /* get_pt_mode */ \ NULL, /* set_policing */ \ NULL, /* get_qos_type */ \ NULL, /* get_qos_capabilities */ \ diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index bba4de378..5ad924469 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -3276,6 +3276,7 @@ unlock: GET_STATS, \ GET_FEATURES, \ NULL, /* set_advertisements */ \ + NULL, /* get_pt_mode */ \ \ netdev_dpdk_set_policing, \ netdev_dpdk_get_qos_types, \ diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index d189a8615..51d29d54a 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -1382,6 +1382,7 @@ netdev_dummy_update_flags(struct netdev *netdev_, \ NULL, /* get_features */ \ NULL, /* set_advertisements */ \ + NULL, /* get_pt_mode */ \ \ NULL, /* set_policing */ \ NULL, /* get_qos_types */ \ diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 6978c44c7..e1d87019f 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -2843,6 +2843,7 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, \ GET_FEATURES, \ netdev_linux_set_advertisements, \ + NULL, /* get_pt_mode */ \ \ netdev_linux_set_policing, \ netdev_linux_get_qos_types, \ diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index c7a299345..7f3cf984e 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -463,10 +463,13 @@ netdev_gre_build_header(const struct netdev *netdev, greh = netdev_tnl_ip_build_header(data, params, IPPROTO_GRE); - if (tnl_cfg->is_layer3) { - greh->protocol = params->flow->dl_type; - } else { + if (params->flow->packet_type == htonl(PT_ETH)) { greh->protocol = htons(ETH_TYPE_TEB); + } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) { + greh->protocol = pt_ns_type_be(params->flow->packet_type); + } else { + ovs_mutex_unlock(&dev->mutex); + return 1; } greh->flags = 0; @@ -575,8 +578,10 @@ netdev_vxlan_build_header(const struct netdev *netdev, put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS | VXLAN_HF_GPE)); put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(params->flow->tunnel.tun_id) << 8)); - if (tnl_cfg->is_layer3) { - switch (ntohs(params->flow->dl_type)) { + if (params->flow->packet_type == htonl(PT_ETH)) { + vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET; + } else if (pt_ns(params->flow->packet_type) == OFPHTN_ETHERTYPE) { + switch (pt_ns_type(params->flow->packet_type)) { case ETH_TYPE_IP: vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_IPV4; break; @@ -586,9 +591,11 @@ netdev_vxlan_build_header(const struct netdev *netdev, case ETH_TYPE_TEB: vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET; break; + default: + goto drop; } } else { - vxh->vx_gpe.next_protocol = VXLAN_GPE_NP_ETHERNET; + goto drop; } } else { put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); @@ -600,6 +607,10 @@ netdev_vxlan_build_header(const struct netdev *netdev, data->header_len += sizeof *vxh; data->tnl_type = OVS_VPORT_TYPE_VXLAN; return 0; + +drop: + ovs_mutex_unlock(&dev->mutex); + return 1; } struct dp_packet * diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 79143d2c8..3c3c18113 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -474,6 +474,12 @@ struct netdev_class { int (*set_advertisements)(struct netdev *netdev, enum netdev_features advertise); + /* Returns 'netdev''s configured packet_type mode. + * + * This function may be set to null if it would always return + * NETDEV_PT_LEGACY_L2. */ + enum netdev_pt_mode (*get_pt_mode)(const struct netdev *netdev); + /* Attempts to set input rate limiting (policing) policy, such that up to * 'kbits_rate' kbps of traffic is accepted, with a maximum accumulative * burst size of 'kbits' kb. diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 640cdbe9c..7de58b8a3 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -98,18 +98,6 @@ netdev_vport_is_patch(const struct netdev *netdev) return class->get_config == get_patch_config; } -bool -netdev_vport_is_layer3(const struct netdev *dev) -{ - if (is_vport_class(netdev_get_class(dev))) { - struct netdev_vport *vport = netdev_vport_cast(dev); - - return vport->tnl_cfg.is_layer3; - } - - return false; -} - static bool netdev_vport_needs_dst_port(const struct netdev *dev) { @@ -407,6 +395,30 @@ parse_tunnel_ip(const char *value, bool accept_mcast, bool *flow, return 0; } +enum tunnel_layers { + TNL_L2 = 1 << 0, /* 1 if a tunnel type can carry Ethernet traffic. */ + TNL_L3 = 1 << 1 /* 1 if a tunnel type can carry L3 traffic. */ +}; +static enum tunnel_layers +tunnel_supported_layers(const char *type, + const struct netdev_tunnel_config *tnl_cfg) +{ + if (!strcmp(type, "lisp")) { + return TNL_L3; + } else if (!strcmp(type, "gre")) { + return TNL_L2 | TNL_L3; + } else if (!strcmp(type, "vxlan") && tnl_cfg->exts & OVS_VXLAN_EXT_GPE) { + return TNL_L2 | TNL_L3; + } else { + return TNL_L2; + } +} +static enum netdev_pt_mode +default_pt_mode(enum tunnel_layers layers) +{ + return layers == TNL_L3 ? NETDEV_PT_LEGACY_L3 : NETDEV_PT_LEGACY_L2; +} + static int set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) { @@ -414,16 +426,14 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) const char *name = netdev_get_name(dev_); const char *type = netdev_get_type(dev_); struct ds errors = DS_EMPTY_INITIALIZER; - bool needs_dst_port, has_csum, optional_layer3; + bool needs_dst_port, has_csum; uint16_t dst_proto = 0, src_proto = 0; struct netdev_tunnel_config tnl_cfg; struct smap_node *node; - bool is_layer3 = false; int err; has_csum = strstr(type, "gre") || strstr(type, "geneve") || strstr(type, "stt") || strstr(type, "vxlan"); - optional_layer3 = !strcmp(type, "gre"); memset(&tnl_cfg, 0, sizeof tnl_cfg); /* Add a default destination port for tunnel ports if none specified. */ @@ -437,7 +447,6 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) if (!strcmp(type, "lisp")) { tnl_cfg.dst_port = htons(LISP_DST_PORT); - tnl_cfg.is_layer3 = true; } if (!strcmp(type, "stt")) { @@ -501,9 +510,10 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) } } else if (!strcmp(node->key, "key") || !strcmp(node->key, "in_key") || - !strcmp(node->key, "out_key")) { + !strcmp(node->key, "out_key") || + !strcmp(node->key, "packet_type")) { /* Handled separately below. */ - } else if (!strcmp(node->key, "exts")) { + } else if (!strcmp(node->key, "exts") && !strcmp(type, "vxlan")) { char *str = xstrdup(node->value); char *ext, *save_ptr = NULL; @@ -515,7 +525,6 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GBP); } else if (!strcmp(type, "vxlan") && !strcmp(ext, "gpe")) { tnl_cfg.exts |= (1 << OVS_VXLAN_EXT_GPE); - optional_layer3 = true; } else { ds_put_format(&errors, "%s: unknown extension '%s'\n", name, ext); @@ -528,21 +537,44 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args, char **errp) } else if (!strcmp(node->key, "egress_pkt_mark")) { tnl_cfg.egress_pkt_mark = strtoul(node->value, NULL, 10); tnl_cfg.set_egress_pkt_mark = true; - } else if (!strcmp(node->key, "layer3")) { - if (!strcmp(node->value, "true")) { - is_layer3 = true; - } } else { ds_put_format(&errors, "%s: unknown %s argument '%s'\n", name, type, node->key); } } - if (optional_layer3 && is_layer3) { - tnl_cfg.is_layer3 = is_layer3; - } else if (!optional_layer3 && is_layer3) { - ds_put_format(&errors, "%s: unknown %s argument '%s'\n", - name, type, "layer3"); + enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg); + const char *full_type = (strcmp(type, "vxlan") ? type + : tnl_cfg.exts & OVS_VXLAN_EXT_GPE ? "VXLAN-GPE" + : "VXLAN (without GPE"); + const char *packet_type = smap_get(args, "packet_type"); + if (!packet_type) { + tnl_cfg.pt_mode = default_pt_mode(layers); + } else if (!strcmp(packet_type, "legacy_l2")) { + tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L2; + if (!(layers & TNL_L2)) { + ds_put_format(&errors, "%s: legacy_l2 configured on %s tunnel " + "that cannot carry L2 traffic\n", + name, full_type); + err = EINVAL; + goto out; + } + } else if (!strcmp(packet_type, "legacy_l3")) { + tnl_cfg.pt_mode = NETDEV_PT_LEGACY_L3; + if (!(layers & TNL_L3)) { + ds_put_format(&errors, "%s: legacy_l3 configured on %s tunnel " + "that cannot carry L3 traffic\n", + name, full_type); + err = EINVAL; + goto out; + } + } else if (!strcmp(packet_type, "ptap")) { + tnl_cfg.pt_mode = NETDEV_PT_AWARE; + } else { + ds_put_format(&errors, "%s: unknown packet_type '%s'\n", + name, packet_type); + err = EINVAL; + goto out; } if (!ipv6_addr_is_set(&tnl_cfg.ipv6_dst) && !tnl_cfg.ip_dst_flow) { @@ -675,9 +707,12 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) smap_add(args, "csum", "true"); } - if (tnl_cfg.is_layer3 && (!strcmp("gre", type) || - !strcmp("vxlan", type))) { - smap_add(args, "layer3", "true"); + enum tunnel_layers layers = tunnel_supported_layers(type, &tnl_cfg); + if (tnl_cfg.pt_mode != default_pt_mode(layers)) { + smap_add(args, "packet_type", + tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2" + : tnl_cfg.pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3" + : "ptap"); } if (!tnl_cfg.dont_fragment) { @@ -809,6 +844,15 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats) return 0; } +static enum netdev_pt_mode +get_pt_mode(const struct netdev *netdev) +{ + struct netdev_vport *dev = netdev_vport_cast(netdev); + + return dev->tnl_cfg.pt_mode; +} + + #ifdef __linux__ static int @@ -873,6 +917,7 @@ netdev_vport_get_ifindex(const struct netdev *netdev_) \ NULL, /* get_features */ \ NULL, /* set_advertisements */ \ + get_pt_mode, \ \ NULL, /* set_policing */ \ NULL, /* get_qos_types */ \ diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h index 048aa6ebf..9d756a265 100644 --- a/lib/netdev-vport.h +++ b/lib/netdev-vport.h @@ -31,7 +31,6 @@ void netdev_vport_tunnel_register(void); void netdev_vport_patch_register(void); bool netdev_vport_is_patch(const struct netdev *); -bool netdev_vport_is_layer3(const struct netdev *); char *netdev_vport_patch_peer(const struct netdev *netdev); diff --git a/lib/netdev.c b/lib/netdev.c index 765bf4b9c..a7840a84e 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -727,6 +727,14 @@ netdev_set_tx_multiq(struct netdev *netdev, unsigned int n_txq) return error; } +enum netdev_pt_mode +netdev_get_pt_mode(const struct netdev *netdev) +{ + return (netdev->netdev_class->get_pt_mode + ? netdev->netdev_class->get_pt_mode(netdev) + : NETDEV_PT_LEGACY_L2); +} + /* Sends 'batch' on 'netdev'. Returns 0 if successful (for every packet), * otherwise a positive errno value. Returns EAGAIN without blocking if * at least one the packets cannot be queued immediately. Returns EMSGSIZE diff --git a/lib/netdev.h b/lib/netdev.h index 31846fabf..998f942e2 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -71,6 +71,32 @@ struct smap; struct sset; struct ovs_action_push_tnl; +enum netdev_pt_mode { + /* The netdev is packet type aware. It can potentially carry any kind of + * packet. This "modern" mode is appropriate for both netdevs that handle + * only a single kind of packet (such as a virtual or physical Ethernet + * interface) and for those that can handle multiple (such as VXLAN-GPE or + * Geneve). */ + NETDEV_PT_AWARE, + + /* The netdev sends and receives only Ethernet frames. The netdev cannot + * carry packets other than Ethernet frames. This is a legacy mode for + * backward compability with controllers that are not prepared to handle + * OpenFlow 1.5+ "packet_type". */ + NETDEV_PT_LEGACY_L2, + + /* The netdev sends and receives only IPv4 and IPv6 packets. The netdev + * cannot carry Ethernet frames or other kinds of packets. + * + * IPv4 and IPv6 packets carried over the netdev are treated as Ethernet: + * when they are received, they are converted to Ethernet by adding a dummy + * header with the proper Ethertype; on tranmission, the Ethernet header is + * stripped. This is a legacy mode for backward compability with + * controllers that are not prepared to handle OpenFlow 1.5+ + * "packet_type". */ + NETDEV_PT_LEGACY_L3, +}; + /* Configuration specific to tunnels. */ struct netdev_tunnel_config { bool in_key_present; @@ -100,7 +126,7 @@ struct netdev_tunnel_config { bool csum; bool dont_fragment; - bool is_layer3; + enum netdev_pt_mode pt_mode; }; void netdev_run(void); @@ -140,6 +166,7 @@ void netdev_mtu_user_config(struct netdev *, bool); bool netdev_mtu_is_user_config(struct netdev *); int netdev_get_ifindex(const struct netdev *); int netdev_set_tx_multiq(struct netdev *, unsigned int n_txq); +enum netdev_pt_mode netdev_get_pt_mode(const struct netdev *); /* Packet reception. */ int netdev_rxq_open(struct netdev *, struct netdev_rxq **, int id); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 0fe6584b7..ce364b361 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -165,7 +165,7 @@ struct xport { bool may_enable; /* May be enabled in bonds. */ bool is_tunnel; /* Is a tunnel port. */ - bool is_layer3; /* Is a layer 3 port. */ + enum netdev_pt_mode pt_mode; /* packet_type handling. */ struct cfm *cfm; /* CFM handle or null. */ struct bfd *bfd; /* BFD handle or null. */ @@ -905,7 +905,7 @@ xlate_xport_set(struct xport *xport, odp_port_t odp_port, xport->state = state; xport->stp_port_no = stp_port_no; xport->is_tunnel = is_tunnel; - xport->is_layer3 = netdev_vport_is_layer3(netdev); + xport->pt_mode = netdev_get_pt_mode(netdev); xport->may_enable = may_enable; xport->odp_port = odp_port; @@ -2691,7 +2691,10 @@ xlate_normal(struct xlate_ctx *ctx) /* Learn source MAC. */ bool is_grat_arp = is_gratuitous_arp(flow, wc); - if (ctx->xin->allow_side_effects && !in_port->is_layer3) { + if (ctx->xin->allow_side_effects + && flow->packet_type == htonl(PT_ETH) + && in_port->pt_mode != NETDEV_PT_LEGACY_L3 + ) { update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, is_grat_arp); } @@ -3351,15 +3354,19 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, return; } - if (flow->packet_type == htonl(PT_ETH) && xport->is_layer3) { - /* Ethernet packet to L3 outport -> pop ethernet header. */ - flow->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, - ntohs(flow->dl_type)); - } else if (flow->packet_type != htonl(PT_ETH) && !xport->is_layer3) { - /* L2 outport and non-ethernet packet_type -> add dummy eth header. */ - flow->packet_type = htonl(PT_ETH); - flow->dl_dst = eth_addr_zero; - flow->dl_src = eth_addr_zero; + if (flow->packet_type == htonl(PT_ETH)) { + /* Strip Ethernet header for legacy L3 port. */ + if (xport->pt_mode == NETDEV_PT_LEGACY_L3) { + flow->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, + ntohs(flow->dl_type)); + } + } else { + /* Add dummy Ethernet header for legacy L2 port. */ + if (xport->pt_mode == NETDEV_PT_LEGACY_L2) { + flow->packet_type = htonl(PT_ETH); + flow->dl_dst = eth_addr_zero; + flow->dl_src = eth_addr_zero; + } } if (xport->peer) { @@ -6394,8 +6401,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) struct xport *in_port = get_ofp_port(xbridge, ctx.base_flow.in_port.ofp_port); - if (flow->packet_type != htonl(PT_ETH) && in_port && in_port->is_layer3 && - ctx.table_id == 0) { + if (flow->packet_type != htonl(PT_ETH) && in_port && + in_port->pt_mode == NETDEV_PT_LEGACY_L3 && ctx.table_id == 0) { /* Add dummy Ethernet header to non-L2 packet if it's coming from a * L3 port. So all packets will be L2 packets for lookup. * The dl_type has already been set from the packet_type. */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index cc325ddd7..d19d486d9 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -2893,7 +2893,7 @@ bundle_update(struct ofbundle *bundle) bundle->floodable = true; LIST_FOR_EACH (port, bundle_node, &bundle->ports) { if (port->up.pp.config & OFPUTIL_PC_NO_FLOOD - || netdev_vport_is_layer3(port->up.netdev) + || netdev_get_pt_mode(port->up.netdev) == NETDEV_PT_LEGACY_L3 || (bundle->ofproto->stp && !stp_forward_in_state(port->stp_state)) || (bundle->ofproto->rstp && !rstp_forward_in_state(port->rstp_state))) { bundle->floodable = false; @@ -2942,7 +2942,7 @@ bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port, port->bundle = bundle; ovs_list_push_back(&bundle->ports, &port->bundle_node); if (port->up.pp.config & OFPUTIL_PC_NO_FLOOD - || netdev_vport_is_layer3(port->up.netdev) + || netdev_get_pt_mode(port->up.netdev) == NETDEV_PT_LEGACY_L3 || (bundle->ofproto->stp && !stp_forward_in_state(port->stp_state)) || (bundle->ofproto->rstp && !rstp_forward_in_state(port->rstp_state))) { bundle->floodable = false; diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index fa99b3102..c6856a09e 100644 --- a/ofproto/tunnel.c +++ b/ofproto/tunnel.c @@ -50,7 +50,7 @@ struct tnl_match { bool in_key_flow; bool ip_src_flow; bool ip_dst_flow; - bool is_layer3; + enum netdev_pt_mode pt_mode; }; struct tnl_port { @@ -164,7 +164,7 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev, tnl_port->match.ip_dst_flow = cfg->ip_dst_flow; tnl_port->match.in_key_flow = cfg->in_key_flow; tnl_port->match.odp_port = odp_port; - tnl_port->match.is_layer3 = netdev_vport_is_layer3(netdev); + tnl_port->match.pt_mode = netdev_get_pt_mode(netdev); map = tnl_match_map(&tnl_port->match); existing_port = tnl_find_exact(&tnl_port->match, *map); @@ -564,8 +564,20 @@ tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock) match.in_key_flow = in_key_flow; match.ip_dst_flow = ip_dst_flow; match.ip_src_flow = ip_src == IP_SRC_FLOW; - match.is_layer3 = flow->packet_type != htonl(PT_ETH); + /* Look for a legacy L2 or L3 tunnel port first. */ + if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) { + match.pt_mode = NETDEV_PT_LEGACY_L3; + } else { + match.pt_mode = NETDEV_PT_LEGACY_L2; + } + tnl_port = tnl_find_exact(&match, map); + if (tnl_port) { + return tnl_port; + } + + /* Then check for a packet type aware port. */ + match.pt_mode = NETDEV_PT_AWARE; tnl_port = tnl_find_exact(&match, map); if (tnl_port) { return tnl_port; @@ -614,11 +626,12 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds) } else { ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key)); } - if (match->is_layer3) { - ds_put_cstr(ds, ", layer3"); - } - ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port); + const char *pt_mode + = (match->pt_mode == NETDEV_PT_LEGACY_L2 ? "legacy_l2" + : match->pt_mode == NETDEV_PT_LEGACY_L3 ? "legacy_l3" + : "ptap"); + ds_put_format(ds, ", %s, dp port=%"PRIu32, pt_mode, match->odp_port); } static void diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at index 228a9af43..9ff7c897c 100644 --- a/tests/tunnel-push-pop-ipv6.at +++ b/tests/tunnel-push-pop-ipv6.at @@ -13,7 +13,7 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \ -- add-port int-br t4 -- set Interface t4 type=geneve \ options:remote_ip=flow options:key=123 ofport_request=5\ -- add-port int-br t5 -- set Interface t5 type=gre \ - options:remote_ip=2001:cafe::92 options:key=455 options:layer3=true ofport_request=6\ + options:remote_ip=2001:cafe::92 options:key=455 options:packet_type=legacy_l3 ofport_request=6\ ], [0]) AT_CHECK([ovs-appctl dpif/show], [0], [dnl @@ -27,7 +27,7 @@ dummy@ovs-dummy: hit:0 missed:0 t2 2/4789: (vxlan: key=123, remote_ip=2001:cafe::92) t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=2001:cafe::93) t4 5/6081: (geneve: key=123, remote_ip=flow) - t5 6/3: (gre: key=455, layer3=true, remote_ip=2001:cafe::92) + t5 6/3: (gre: key=455, packet_type=legacy_l3, remote_ip=2001:cafe::92) ]) dnl First setup dummy interface IP address, then add the route diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index 5a2c42383..c376e719e 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -15,7 +15,7 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \ -- add-port int-br t5 -- set Interface t5 type=geneve \ options:remote_ip=1.1.2.93 options:out_key=flow options:egress_pkt_mark=1234 ofport_request=6\ -- add-port int-br t6 -- set Interface t6 type=gre \ - options:remote_ip=1.1.2.92 options:key=456 options:layer3=true ofport_request=7\ + options:remote_ip=1.1.2.92 options:key=456 options:packet_type=legacy_l3 ofport_request=7\ -- add-port int-br t7 -- set Interface t7 type=vxlan \ options:remote_ip=1.1.2.92 options:key=345 options:exts=gpe ofport_request=8\ ], [0]) @@ -32,7 +32,7 @@ dummy@ovs-dummy: hit:0 missed:0 t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=1.1.2.93) t4 5/6081: (geneve: key=123, remote_ip=flow) t5 6/6081: (geneve: egress_pkt_mark=1234, out_key=flow, remote_ip=1.1.2.93) - t6 7/3: (gre: key=456, layer3=true, remote_ip=1.1.2.92) + t6 7/3: (gre: key=456, packet_type=legacy_l3, remote_ip=1.1.2.92) t7 8/4789: (vxlan: key=345, remote_ip=1.1.2.92) ]) diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 500f05a24..abfe3976b 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2402,6 +2402,31 @@ including tunnel monitoring. </column> + <group title="Tunnel Options: lisp only"> + <column name="options" key="packet_type" + type='{"type": "string", "enum": ["set", + ["legacy_l3", "ptap"]]}'> + <p> + A LISP tunnel sends and receives only IPv4 and IPv6 packets. This + option controls what how the tunnel represents the packets that it + sends and receives: + </p> + + <ul> + <li> + By default, or if this option is <code>legacy_l3</code>, the + tunnel represents packets as Ethernet frames for compatibility + with legacy OpenFlow controllers that expect this behavior. + </li> + <li> + If this option is <code>ptap</code>, the tunnel represents + packets using the <code>packet_type</code> mechanism introduced + in OpenFlow 1.5. + </li> + </ul> + </column> + </group> + <group title="Tunnel Options: vxlan only"> <column name="options" key="exts"> @@ -2421,21 +2446,42 @@ <code>gpe</code>: Support for Generic Protocol Encapsulation in accordance with IETF draft <code>https://tools.ietf.org/html/draft-ietf-nvo3-vxlan-gpe</code>. + Without this option, a VXLAN packet always encapsulates an + Ethernet frame. With this option, an VXLAN packet may also + encapsulate an IPv4, IPv6, NSH, or MPLS packet. </li> </ul> </column> - <column name="options" key="layer3" type='{"type": "boolean"}'> + <column name="options" key="packet_type" + type='{"type": "string", "enum": ["set", + ["legacy_l2", "legacy_l3", "ptap"]]}'> <p> - By default, or if set to false, the tunnel carries L2 packets (with - an Ethernet header). If set to true, the tunnel carries L3 packets - (without an Ethernet header present). + This option controls what types of packets the tunnel sends and + receives and how it represents them: </p> - <p> - To set this option to true, the <code>gpe</code> extension must - also be enabled in <ref column="options" key="exts"/>. - </p> + <ul> + <li> + By default, or if this option is <code>legacy_l2</code>, the + tunnel sends and receives only Ethernet frames. + </li> + <li> + If this option is <code>legacy_l3</code>, the tunnel sends and + receives only non-Ethernet (L3) packet, but the packets are + represented as Ethernet frames for compatibility with legacy + OpenFlow controllers that expect this behavior. This requires + enabling <code>gpe</code> in <ref column="options" key="exts"/>. + </li> + <li> + If this option is <code>ptap</code>, Open vSwitch represents + packets in the tunnel using the <code>packet_type</code> + mechanism introduced in OpenFlow 1.5. This mechanism supports + any kind of packet, but actually sending and receiving + non-Ethernet packets requires additionally enabling + <code>gpe</code> in <ref column="options" key="exts"/>. + </li> + </ul> </column> </group> @@ -2444,18 +2490,32 @@ <code>gre</code> interfaces support these options. </p> - <column name="options" key="layer3" type='{"type": "boolean"}'> + <column name="options" key="packet_type" + type='{"type": "string", "enum": ["set", + ["legacy_l2", "legacy_l3", "ptap"]]}'> <p> - By default, or if set to false, the tunnel carries L2 packets (with - an Ethernet header). If set to true, the tunnel carries L3 packets - (without an Ethernet header present). + This option controls what types of packets the tunnel sends and + receives and how it represents them: </p> - <p> - A single GRE tunnel cannot carry both L2 and L3 packets, but the - same effect can be realized by creating two tunnels with different - <code>layer3</code> settings and otherwise the same configuration. - </p> + <ul> + <li> + By default, or if this option is <code>legacy_l2</code>, the + tunnel sends and receives only Ethernet frames. + </li> + <li> + If this option is <code>legacy_l3</code>, the tunnel sends and + receives only non-Ethernet (L3) packet, but the packets are + represented as Ethernet frames for compatibility with legacy + OpenFlow controllers that expect this behavior. + </li> + <li> + If this option is <code>ptap</code>, the tunnel sends and + receives any kind of packet. Open vSwitch represents packets in + the tunnel using the <code>packet_type</code> mechanism + introduced in OpenFlow 1.5. + </li> + </ul> </column> </group> |