X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fnetdev-vport.c;h=a3394dd6359497749f9eb847aba3a7adb873a02f;hb=35303d715b1f0db46e6a27146815061a60385dc6;hp=ed407dcb0cfad64253c89447c055debade832b71;hpb=e5a1caeed45ae4dc8783a2fc1ea466c9e1cc79a7;p=cascardo%2Fovs.git diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index ed407dcb0..a3394dd63 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -55,6 +55,7 @@ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); #define GENEVE_DST_PORT 6081 #define VXLAN_DST_PORT 4789 #define LISP_DST_PORT 4341 +#define STT_DST_PORT 7471 #define VXLAN_HLEN (sizeof(struct eth_header) + \ sizeof(struct ip_header) + \ @@ -158,7 +159,7 @@ netdev_vport_needs_dst_port(const struct netdev *dev) return (class->get_config == get_tunnel_config && (!strcmp("geneve", type) || !strcmp("vxlan", type) || - !strcmp("lisp", type))); + !strcmp("lisp", type) || !strcmp("stt", type)) ); } const char * @@ -257,8 +258,12 @@ netdev_vport_construct(struct netdev *netdev_) dev->tnl_cfg.dst_port = htons(VXLAN_DST_PORT); } else if (!strcmp(type, "lisp")) { dev->tnl_cfg.dst_port = htons(LISP_DST_PORT); + } else if (!strcmp(type, "stt")) { + dev->tnl_cfg.dst_port = htons(STT_DST_PORT); } + dev->tnl_cfg.dont_fragment = true; + dev->tnl_cfg.ttl = DEFAULT_TTL; return 0; } @@ -432,7 +437,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) struct smap_node *node; has_csum = strstr(type, "gre") || strstr(type, "geneve") || - strstr(type, "vxlan"); + strstr(type, "stt") || strstr(type, "vxlan"); ipsec_mech_set = false; memset(&tnl_cfg, 0, sizeof tnl_cfg); @@ -449,6 +454,10 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args) tnl_cfg.dst_port = htons(LISP_DST_PORT); } + if (!strcmp(type, "stt")) { + tnl_cfg.dst_port = htons(STT_DST_PORT); + } + needs_dst_port = netdev_vport_needs_dst_port(dev_); tnl_cfg.ipsec = strstr(type, "ipsec"); tnl_cfg.dont_fragment = true; @@ -688,7 +697,8 @@ get_tunnel_config(const struct netdev *dev, struct smap *args) if ((!strcmp("geneve", type) && dst_port != GENEVE_DST_PORT) || (!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) || - (!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) { + (!strcmp("lisp", type) && dst_port != LISP_DST_PORT) || + (!strcmp("stt", type) && dst_port != STT_DST_PORT)) { smap_add_format(args, "dst_port", "%d", dst_port); } } @@ -891,6 +901,18 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl) return NULL; } + if (udp->udp_csum) { + uint32_t csum = packet_csum_pseudoheader(dp_packet_l3(packet)); + + csum = csum_continue(csum, udp, dp_packet_size(packet) - + ((const unsigned char *)udp - + (const unsigned char *)dp_packet_l2(packet))); + if (csum_finish(csum)) { + return NULL; + } + tnl->flags |= FLOW_TNL_F_CSUM; + } + tnl->tp_src = udp->udp_src; tnl->tp_dst = udp->udp_dst; @@ -902,30 +924,41 @@ get_src_port(struct dp_packet *packet) { uint32_t hash; - hash = dp_packet_get_dp_hash(packet); + hash = dp_packet_get_rss_hash(packet); return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) + tnl_udp_port_min); } -static void * -push_udp_header(struct dp_packet *packet, const void *header, int size) +static void +push_udp_header(struct dp_packet *packet, + const struct ovs_action_push_tnl *data) { struct udp_header *udp; int ip_tot_size; - udp = push_ip_header(packet, header, size, &ip_tot_size); + udp = push_ip_header(packet, data->header, data->header_len, &ip_tot_size); /* set udp src port */ udp->udp_src = get_src_port(packet); udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header)); - /* udp_csum is zero */ - return udp + 1; + if (udp->udp_csum) { + uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet))); + + csum = csum_continue(csum, udp, + ip_tot_size - sizeof (struct ip_header)); + udp->udp_csum = csum_finish(csum); + + if (!udp->udp_csum) { + udp->udp_csum = htons(0xffff); + } + } } static void * udp_build_header(struct netdev_tunnel_config *tnl_cfg, + const struct flow *tnl_flow, struct ovs_action_push_tnl *data) { struct ip_header *ip; @@ -937,6 +970,13 @@ udp_build_header(struct netdev_tunnel_config *tnl_cfg, udp = (struct udp_header *) (ip + 1); udp->udp_dst = tnl_cfg->dst_port; + if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) { + /* Write a value in now to mark that we should compute the checksum + * later. 0xffff is handy because it is transparent to the + * calculation. */ + udp->udp_csum = htons(0xffff); + } + return udp + 1; } @@ -1012,52 +1052,46 @@ parse_gre_header(struct dp_packet *packet, } static void -reset_tnl_md(struct pkt_metadata *md) +pkt_metadata_init_tnl(struct pkt_metadata *md) { - memset(&md->tunnel, 0, sizeof(md->tunnel)); + memset(md, 0, offsetof(struct pkt_metadata, tunnel.metadata)); + + /* If 'opt_map' is zero then none of the rest of the tunnel metadata + * will be read, so we can skip clearing it. */ + md->tunnel.metadata.opt_map = 0; } -static void -gre_extract_md(struct dp_packet *packet) +static int +netdev_gre_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; int hlen = sizeof(struct eth_header) + sizeof(struct ip_header) + 4; - memset(md, 0, sizeof *md); + pkt_metadata_init_tnl(md); if (hlen > dp_packet_size(packet)) { - return; + return EINVAL; } hlen = parse_gre_header(packet, tnl); if (hlen < 0) { - reset_tnl_md(md); + return -hlen; } dp_packet_reset_packet(packet, hlen); -} -static int -netdev_gre_pop_header(struct netdev *netdev_ OVS_UNUSED, - struct dp_packet **pkt, int cnt) -{ - int i; - - for (i = 0; i < cnt; i++) { - gre_extract_md(pkt[i]); - } return 0; } static void -netdev_gre_push_header__(struct dp_packet *packet, - const void *header, int size) +netdev_gre_push_header(struct dp_packet *packet, + const struct ovs_action_push_tnl *data) { struct gre_base_hdr *greh; int ip_tot_size; - greh = push_ip_header(packet, header, size, &ip_tot_size); + greh = push_ip_header(packet, data->header, data->header_len, &ip_tot_size); if (greh->flags & htons(GRE_CSUM)) { ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1); @@ -1065,21 +1099,6 @@ netdev_gre_push_header__(struct dp_packet *packet, } } -static int -netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED, - struct dp_packet **packets, int cnt, - const struct ovs_action_push_tnl *data) -{ - int i; - - for (i = 0; i < cnt; i++) { - netdev_gre_push_header__(packets[i], data->header, data->header_len); - packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); - } - return 0; -} - - static int netdev_gre_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data, @@ -1127,21 +1146,21 @@ netdev_gre_build_header(const struct netdev *netdev, return 0; } -static void -vxlan_extract_md(struct dp_packet *packet) +static int +netdev_vxlan_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; struct vxlanhdr *vxh; - memset(md, 0, sizeof *md); + pkt_metadata_init_tnl(md); if (VXLAN_HLEN > dp_packet_size(packet)) { - return; + return EINVAL; } vxh = udp_extract_tnl_md(packet, tnl); if (!vxh) { - return; + return EINVAL; } if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) || @@ -1149,24 +1168,13 @@ vxlan_extract_md(struct dp_packet *packet) VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n", ntohl(get_16aligned_be32(&vxh->vx_flags)), ntohl(get_16aligned_be32(&vxh->vx_vni))); - reset_tnl_md(md); - return; + return EINVAL; } tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8); tnl->flags |= FLOW_TNL_F_KEY; dp_packet_reset_packet(packet, VXLAN_HLEN); -} - -static int -netdev_vxlan_pop_header(struct netdev *netdev_ OVS_UNUSED, - struct dp_packet **pkt, int cnt) -{ - int i; - for (i = 0; i < cnt; i++) { - vxlan_extract_md(pkt[i]); - } return 0; } @@ -1183,7 +1191,7 @@ netdev_vxlan_build_header(const struct netdev *netdev, ovs_mutex_lock(&dev->mutex); tnl_cfg = &dev->tnl_cfg; - vxh = udp_build_header(tnl_cfg, data); + vxh = udp_build_header(tnl_cfg, tnl_flow, data); put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS)); put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); @@ -1195,83 +1203,57 @@ netdev_vxlan_build_header(const struct netdev *netdev, } static int -netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED, - struct dp_packet **packets, int cnt, - const struct ovs_action_push_tnl *data) -{ - int i; - - for (i = 0; i < cnt; i++) { - push_udp_header(packets[i], data->header, VXLAN_HLEN); - packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); - } - return 0; -} - -static void -geneve_extract_md(struct dp_packet *packet) +netdev_geneve_pop_header(struct dp_packet *packet) { struct pkt_metadata *md = &packet->md; struct flow_tnl *tnl = &md->tunnel; struct genevehdr *gnh; unsigned int hlen; + int err; - memset(md, 0, sizeof *md); + pkt_metadata_init_tnl(md); if (GENEVE_BASE_HLEN > dp_packet_size(packet)) { VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%u\n", (unsigned int)GENEVE_BASE_HLEN, dp_packet_size(packet)); - return; + return EINVAL; } gnh = udp_extract_tnl_md(packet, tnl); if (!gnh) { - return; + return EINVAL; } hlen = GENEVE_BASE_HLEN + gnh->opt_len * 4; if (hlen > dp_packet_size(packet)) { VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n", hlen, dp_packet_size(packet)); - reset_tnl_md(md); - return; + return EINVAL; } if (gnh->ver != 0) { VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver); - reset_tnl_md(md); - return; - } - - if (gnh->opt_len && gnh->critical) { - VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n", - gnh->opt_len * 4); - reset_tnl_md(md); - return; + return EINVAL; } if (gnh->proto_type != htons(ETH_TYPE_TEB)) { VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n", ntohs(gnh->proto_type)); - reset_tnl_md(md); - return; + return EINVAL; } tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0; tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8); tnl->flags |= FLOW_TNL_F_KEY; - dp_packet_reset_packet(packet, hlen); -} + err = tun_metadata_from_geneve_header(gnh->options, gnh->opt_len * 4, + &tnl->metadata); + if (err) { + VLOG_WARN_RL(&err_rl, "invalid geneve options"); + return err; + } -static int -netdev_geneve_pop_header(struct netdev *netdev_ OVS_UNUSED, - struct dp_packet **pkt, int cnt) -{ - int i; + dp_packet_reset_packet(packet, hlen); - for (i = 0; i < cnt; i++) { - geneve_extract_md(pkt[i]); - } return 0; } @@ -1283,34 +1265,29 @@ netdev_geneve_build_header(const struct netdev *netdev, struct netdev_vport *dev = netdev_vport_cast(netdev); struct netdev_tunnel_config *tnl_cfg; struct genevehdr *gnh; + int opt_len; + bool crit_opt; /* XXX: RCUfy tnl_cfg. */ ovs_mutex_lock(&dev->mutex); tnl_cfg = &dev->tnl_cfg; - gnh = udp_build_header(tnl_cfg, data); + gnh = udp_build_header(tnl_cfg, tnl_flow, data); - gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM); - gnh->proto_type = htons(ETH_TYPE_TEB); put_16aligned_be32(&gnh->vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8)); ovs_mutex_unlock(&dev->mutex); - data->header_len = GENEVE_BASE_HLEN; - data->tnl_type = OVS_VPORT_TYPE_GENEVE; - return 0; -} -static int -netdev_geneve_push_header(const struct netdev *netdev OVS_UNUSED, - struct dp_packet **packets, int cnt, - const struct ovs_action_push_tnl *data) -{ - int i; + opt_len = tun_metadata_to_geneve_header(&tnl_flow->tunnel.metadata, + gnh->options, &crit_opt); - for (i = 0; i < cnt; i++) { - push_udp_header(packets[i], data->header, data->header_len); - packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port)); - } + gnh->opt_len = opt_len / 4; + gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM); + gnh->critical = crit_opt ? 1 : 0; + gnh->proto_type = htons(ETH_TYPE_TEB); + + data->header_len = GENEVE_BASE_HLEN + opt_len; + data->tnl_type = OVS_VPORT_TYPE_GENEVE; return 0; } @@ -1444,7 +1421,7 @@ netdev_vport_tunnel_register(void) * a port number to the end if one is necessary. */ static const struct vport_class vport_classes[] = { TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header, - netdev_geneve_push_header, + push_udp_header, netdev_geneve_pop_header), TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header, netdev_gre_push_header, @@ -1453,9 +1430,10 @@ netdev_vport_tunnel_register(void) TUNNEL_CLASS("gre64", "gre64_sys", NULL, NULL, NULL), TUNNEL_CLASS("ipsec_gre64", "gre64_sys", NULL, NULL, NULL), TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header, - netdev_vxlan_push_header, + push_udp_header, netdev_vxlan_pop_header), - TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL) + TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL), + TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL), }; static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;