/* Execute a list of actions against 'skb'. */ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb) { struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); struct loop_counter *loop; int error; struct ovs_key_ipv4_tunnel tun_key; /* Check whether we've looped too much. */ loop = &__get_cpu_var(loop_counters); if (unlikely(++loop->count > MAX_LOOPS)) loop->looping = true; if (unlikely(loop->looping)) { error = loop_suppress(dp, acts); kfree_skb(skb); goto out_loop; } OVS_CB(skb)->tun_key = NULL; error = do_execute_actions(dp, skb, acts->actions, acts->actions_len, &tun_key, false); /* Check whether sub-actions looped too much. */ if (unlikely(loop->looping)) error = loop_suppress(dp, acts); out_loop: /* Decrement loop counter. */ if (!--loop->count) loop->looping = false; return error; }
/** * ovs_vport_receive - pass up received packet to the datapath for processing * * @vport: vport that received the packet * @skb: skb that was received * @tun_key: tunnel (if any) that carried packet * * Must be called with rcu_read_lock. The packet cannot be shared and * skb->data should point to the Ethernet header. */ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb, const struct ip_tunnel_info *tun_info) { struct sw_flow_key key; int error; OVS_CB(skb)->input_vport = vport; OVS_CB(skb)->mru = 0; OVS_CB(skb)->cutlen = 0; if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) { u32 mark; mark = skb->mark; skb_scrub_packet(skb, true); skb->mark = mark; tun_info = NULL; } ovs_skb_init_inner_protocol(skb); skb_clear_ovs_gso_cb(skb); /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_key_extract(tun_info, skb, &key); if (unlikely(error)) { kfree_skb(skb); return error; } ovs_dp_process_packet(skb, &key); return 0; }
/* called by execute_plums() to execute BPF program * or send it out of vport if destination plum_id is zero * It's called with rcu_read_lock. */ static void __bpf_forward(struct bpf_dp_context *ctx, u32 dest) { struct datapath *dp = ctx->dp; u32 plum_id = dest >> 16; u32 port_id = dest & 0xffff; struct plum *plum; struct vport *vport; struct ovs_key_ipv4_tunnel tun_key; plum = rcu_dereference(dp->plums[plum_id]); if (unlikely(!plum)) { kfree_skb(ctx->skb); return; } if (plum_id == 0) { if (ctx->context.tun_key.dst_ip) { tun_key.tun_id = cpu_to_be64(ctx->context.tun_key.tun_id); tun_key.ipv4_src = cpu_to_be32(ctx->context.tun_key.src_ip); tun_key.ipv4_dst = cpu_to_be32(ctx->context.tun_key.dst_ip); tun_key.ipv4_tos = ctx->context.tun_key.tos; tun_key.ipv4_ttl = ctx->context.tun_key.ttl; tun_key.tun_flags = TUNNEL_KEY; OVS_CB(ctx->skb)->tun_key = &tun_key; } else { OVS_CB(ctx->skb)->tun_key = NULL; } plum_update_stats(plum, port_id, ctx->skb, false); vport = ovs_vport_rcu(dp, port_id); if (unlikely(!vport)) { kfree_skb(ctx->skb); return; } /** begin_fixme **/ #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) offload_send(vport, ctx->skb); #else ovs_vport_send(vport, ctx->skb); #endif /** end_fixme **/ } else { ctx->context.port_id = port_id; ctx->context.plum_id = plum_id; BUG_ON(plum->run == NULL); plum_update_stats(plum, port_id, ctx->skb, true); /* execute BPF program */ plum->run(ctx); consume_skb(ctx->skb); } }
/* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero * value if 'skb' is freed. */ static int handle_fragments(struct net *net, struct sw_flow_key *key, u16 zone, struct sk_buff *skb) { struct ovs_skb_cb ovs_cb = *OVS_CB(skb); if (key->eth.type == htons(ETH_P_IP)) { enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone; int err; memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); err = ip_defrag(skb, user); if (err) return err; ovs_cb.mru = IPCB(skb)->frag_max_size; #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) } else if (key->eth.type == htons(ETH_P_IPV6)) { enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone; struct sk_buff *reasm; memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); reasm = nf_ct_frag6_gather(skb, user); if (!reasm) return -EINPROGRESS; if (skb == reasm) { kfree_skb(skb); return -EINVAL; } /* Don't free 'skb' even though it is one of the original * fragments, as we're going to morph it into the head. */ skb_get(skb); nf_ct_frag6_consume_orig(reasm); key->ip.proto = ipv6_hdr(reasm)->nexthdr; skb_morph(skb, reasm); skb->next = reasm->next; consume_skb(reasm); ovs_cb.mru = IP6CB(skb)->frag_max_size; #endif } else { kfree_skb(skb); return -EPFNOSUPPORT; } key->ip.frag = OVS_FRAG_TYPE_NONE; skb_clear_hash(skb); skb->ignore_df = 1; *OVS_CB(skb) = ovs_cb; return 0; }
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { struct ovs_key_ipv4_tunnel *tun_key; struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); struct vxlan_metadata md = {0}; struct rtable *rt; __be16 src_port; __be32 saddr; __be16 df; int err; u32 vxflags; if (unlikely(!OVS_CB(skb)->egress_tun_info)) { err = -EINVAL; goto error; } tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; /* Route lookup */ saddr = tun_key->ipv4_src; rt = find_route(ovs_dp_get_net(vport->dp), &saddr, tun_key->ipv4_dst, IPPROTO_UDP, tun_key->ipv4_tos, skb->mark); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; } df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; skb->ignore_df = 1; src_port = udp_flow_src_port(net, skb, 0, 0, true); md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); md.gbp = vxlan_ext_gbp(skb); vxflags = vxlan_port->exts | (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0); err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, &md, false, vxflags); if (err < 0) ip_rt_put(rt); return err; error: kfree_skb(skb); return err; }
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; struct ovs_key_ipv4_tunnel *tun_key; struct rtable *rt; struct flowi4 fl; __be16 src_port; __be16 df; int err; if (unlikely(!OVS_CB(skb)->egress_tun_info)) { err = -EINVAL; goto error; } tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; /* Route lookup */ memset(&fl, 0, sizeof(fl)); fl.daddr = tun_key->ipv4_dst; fl.saddr = tun_key->ipv4_src; fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos); fl.flowi4_mark = skb->mark; fl.flowi4_proto = IPPROTO_UDP; rt = ip_route_output_key(net, &fl); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; } df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; skb->ignore_df = 1; src_port = udp_flow_src_port(net, skb, 0, 0, true); err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, fl.saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, htonl(be64_to_cpu(tun_key->tun_id) << 8), false); if (err < 0) ip_rt_put(rt); return err; error: kfree_skb(skb); return err; }
int ovs_flow_key_extract(struct sk_buff *skb, struct sw_flow_key *key) { /* Extract metadata from packet. */ memset(key, 0, sizeof(*key)); if (OVS_CB(skb)->tun_key) memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key)); key->phy.priority = skb->priority; key->phy.in_port = OVS_CB(skb)->input_vport->port_no; key->phy.skb_mark = skb->mark; return key_extract(skb, key); }
/* Must be called with rcu_read_lock. */ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) { struct datapath *dp = p->dp; struct sw_flow *flow; struct dp_stats_percpu *stats; u64 *stats_counter; int error; stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); if (!OVS_CB(skb)->flow) { struct sw_flow_key key; int key_len; /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_extract(skb, p->port_no, &key, &key_len); if (unlikely(error)) { kfree_skb(skb); return; } /* Look up flow. */ flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len); if (unlikely(!flow)) { struct dp_upcall_info upcall; upcall.cmd = OVS_PACKET_CMD_MISS; upcall.key = &key; upcall.userdata = NULL; upcall.pid = p->upcall_pid; ovs_dp_upcall(dp, skb, &upcall); consume_skb(skb); stats_counter = &stats->n_missed; goto out; } OVS_CB(skb)->flow = flow; } stats_counter = &stats->n_hit; ovs_flow_used(OVS_CB(skb)->flow, skb); ovs_execute_actions(dp, skb); out: /* Update datapath statistics. */ u64_stats_update_begin(&stats->sync); (*stats_counter)++; u64_stats_update_end(&stats->sync); }
static int execute_set_action(struct sk_buff *skb, const struct nlattr *nested_attr, struct ovs_key_ipv4_tunnel *tun_key) { int err = 0; switch (nla_type(nested_attr)) { case OVS_KEY_ATTR_PRIORITY: skb->priority = nla_get_u32(nested_attr); break; case OVS_KEY_ATTR_TUN_ID: if (!OVS_CB(skb)->tun_key) { /* If tun_key is NULL for this skb, assign it to * a value the caller passed in for action processing * and output. This can disappear once we drop support * for setting tun_id outside of tun_key. */ memset(tun_key, 0, sizeof(struct ovs_key_ipv4_tunnel)); OVS_CB(skb)->tun_key = tun_key; } OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr); OVS_CB(skb)->tun_key->tun_flags |= OVS_FLOW_TNL_F_KEY; break; case OVS_KEY_ATTR_IPV4_TUNNEL: OVS_CB(skb)->tun_key = nla_data(nested_attr); break; case OVS_KEY_ATTR_ETHERNET: err = set_eth_addr(skb, nla_data(nested_attr)); break; case OVS_KEY_ATTR_IPV4: err = set_ipv4(skb, nla_data(nested_attr)); break; case OVS_KEY_ATTR_TCP: err = set_tcp(skb, nla_data(nested_attr)); break; case OVS_KEY_ATTR_UDP: err = set_udp(skb, nla_data(nested_attr)); break; } return err; }
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { struct ovs_key_ipv4_tunnel *tun_key; struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); struct rtable *rt; __be16 src_port; __be32 saddr; __be16 df; int port_min; int port_max; int err; if (unlikely(!OVS_CB(skb)->egress_tun_info)) { err = -EINVAL; goto error; } tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; /* Route lookup */ saddr = tun_key->ipv4_src; rt = find_route(ovs_dp_get_net(vport->dp), &saddr, tun_key->ipv4_dst, IPPROTO_UDP, tun_key->ipv4_tos, skb->mark); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; } df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; skb->local_df = 1; inet_get_local_port_range(net, &port_min, &port_max); src_port = vxlan_src_port(port_min, port_max, skb); err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, htonl(be64_to_cpu(tun_key->tun_id) << 8)); if (err < 0) ip_rt_put(rt); error: return err; }
static int bpf_dp_ctx_init(struct bpf_dp_context *ctx) { struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(ctx->skb)->tun_key; if (skb_headroom(ctx->skb) < 64) { if (pskb_expand_head(ctx->skb, 64, 0, GFP_ATOMIC)) return -ENOMEM; } ctx->context.length = ctx->skb->len; ctx->context.vlan_tag = vlan_tx_tag_present(ctx->skb) ? vlan_tx_tag_get(ctx->skb) : 0; ctx->context.hw_csum = (ctx->skb->ip_summed == CHECKSUM_PARTIAL); if (tun_key) { ctx->context.tun_key.tun_id = be32_to_cpu(be64_get_low32(tun_key->tun_id)); ctx->context.tun_key.src_ip = be32_to_cpu(tun_key->ipv4_src); ctx->context.tun_key.dst_ip = be32_to_cpu(tun_key->ipv4_dst); ctx->context.tun_key.tos = tun_key->ipv4_tos; ctx->context.tun_key.ttl = tun_key->ipv4_ttl; } else { memset(&ctx->context.tun_key, 0, sizeof(struct bpf_ipv4_tun_key)); } return 0; }
int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, struct sk_buff *skb, struct sw_flow_key *key) { /* Extract metadata from packet. */ if (tun_info) { memcpy(&key->tun_key, &tun_info->tunnel, sizeof(key->tun_key)); BUILD_BUG_ON(((1 << (sizeof(tun_info->options_len) * 8)) - 1) > sizeof(key->tun_opts)); if (tun_info->options) { memcpy(GENEVE_OPTS(key, tun_info->options_len), tun_info->options, tun_info->options_len); key->tun_opts_len = tun_info->options_len; } else { key->tun_opts_len = 0; } } else { key->tun_opts_len = 0; memset(&key->tun_key, 0, sizeof(key->tun_key)); } key->phy.priority = skb->priority; key->phy.in_port = OVS_CB(skb)->input_vport->port_no; key->phy.skb_mark = skb->mark; key->ovs_flow_hash = 0; key->recirc_id = 0; return key_extract(skb, key); }
static int output_userspace(struct datapath *dp, struct sk_buff *skb, const struct nlattr *attr) { struct dp_upcall_info upcall; const struct nlattr *a; int rem; upcall.cmd = OVS_PACKET_CMD_ACTION; upcall.key = &OVS_CB(skb)->flow->key; upcall.userdata = NULL; upcall.pid = 0; for (a = nla_data(attr), rem = nla_len(attr); rem > 0; a = nla_next(a, &rem)) { switch (nla_type(a)) { case OVS_USERSPACE_ATTR_USERDATA: upcall.userdata = a; break; case OVS_USERSPACE_ATTR_PID: upcall.pid = nla_get_u32(a); break; } } return ovs_dp_upcall(dp, skb, &upcall); }
static void __gre_build_header(struct sk_buff *skb, int tunnel_hlen, bool is_gre64) { const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key; __be32 *options = (__be32 *)(skb_network_header(skb) + tunnel_hlen - GRE_HEADER_SECTION); struct gre_base_hdr *greh = (struct gre_base_hdr *) skb_transport_header(skb); greh->protocol = htons(ETH_P_TEB); greh->flags = 0; /* Work backwards over the options so the checksum is last. */ if (tun_key->tun_flags & OVS_TNL_F_KEY || is_gre64) { greh->flags |= GRE_KEY; if (is_gre64) { /* Set higher 32 bits to seq. */ *options = be64_get_high32(tun_key->tun_id); options--; greh->flags |= GRE_SEQ; } *options = be64_get_low32(tun_key->tun_id); options--; } if (tun_key->tun_flags & OVS_TNL_F_CSUM) { greh->flags |= GRE_CSUM; *options = 0; *(__sum16 *)options = csum_fold(skb_checksum(skb, skb_transport_offset(skb), skb->len - skb_transport_offset(skb), 0)); } }
/* Execute a list of actions against 'skb'. */ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb) { struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); return do_execute_actions(dp, skb, acts->actions, acts->actions_len, false); }
static int __send(struct vport *vport, struct sk_buff *skb, int tunnel_hlen, __be32 seq, __be16 gre64_flag) { struct ovs_key_ipv4_tunnel *tun_key = &OVS_CB(skb)->tun_info->tunnel; struct rtable *rt; int min_headroom; __be16 df; __be32 saddr; int err; /* Route lookup */ saddr = tun_key->ipv4_src; rt = find_route(ovs_dp_get_net(vport->dp), &saddr, tun_key->ipv4_dst, IPPROTO_GRE, tun_key->ipv4_tos, skb->mark); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; } min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len + tunnel_hlen + sizeof(struct iphdr) + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { int head_delta = SKB_DATA_ALIGN(min_headroom - skb_headroom(skb) + 16); err = pskb_expand_head(skb, max_t(int, head_delta, 0), 0, GFP_ATOMIC); if (unlikely(err)) goto err_free_rt; }
static int handle_fragments(struct net *net, struct sw_flow_key *key, u16 zone, struct sk_buff *skb) { struct ovs_skb_cb ovs_cb = *OVS_CB(skb); if (key->eth.type == htons(ETH_P_IP)) { enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone; int err; memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); err = ip_defrag(net, skb, user); if (err) return err; ovs_cb.mru = IPCB(skb)->frag_max_size; } else if (key->eth.type == htons(ETH_P_IPV6)) { #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone; struct sk_buff *reasm; memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); reasm = nf_ct_frag6_gather(net, skb, user); if (!reasm) return -EINPROGRESS; if (skb == reasm) return -EINVAL; key->ip.proto = ipv6_hdr(reasm)->nexthdr; skb_morph(skb, reasm); consume_skb(reasm); ovs_cb.mru = IP6CB(skb)->frag_max_size; #else return -EPFNOSUPPORT; #endif } else { return -EPFNOSUPPORT; } key->ip.frag = OVS_FRAG_TYPE_NONE; skb_clear_hash(skb); skb->ignore_df = 1; *OVS_CB(skb) = ovs_cb; return 0; }
static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct ip_tunnel_info *egress_tun_info) { return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), OVS_CB(skb)->egress_tun_info, IPPROTO_GRE, skb->mark, 0, 0); }
/** * ovs_vport_receive - pass up received packet to the datapath for processing * * @vport: vport that received the packet * @skb: skb that was received * * Must be called with rcu_read_lock. The packet cannot be shared and * skb->data should point to the Ethernet header. The caller must have already * called compute_ip_summed() to initialize the checksumming fields. */ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb) { struct vport_percpu_stats *stats; stats = this_cpu_ptr(vport->percpu_stats); u64_stats_update_begin(&stats->sync); stats->rx_packets++; stats->rx_bytes += skb->len; u64_stats_update_end(&stats->sync); if (!(vport->ops->flags & VPORT_F_FLOW)) OVS_CB(skb)->flow = NULL; if (!(vport->ops->flags & VPORT_F_TUN_ID)) OVS_CB(skb)->tun_key = NULL; ovs_dp_process_received_packet(vport, skb); }
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->sport; struct rtable *rt; struct flowi fl; __be16 src_port; int port_min; int port_max; __be16 df; int err; if (unlikely(!OVS_CB(skb)->tun_key)) { err = -EINVAL; goto error; } /* Route lookup */ memset(&fl, 0, sizeof(fl)); fl.fl4_dst = OVS_CB(skb)->tun_key->ipv4_dst; fl.fl4_src = OVS_CB(skb)->tun_key->ipv4_src; fl.fl4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos); fl.mark = skb->mark; fl.proto = IPPROTO_UDP; err = ip_route_output_key(net, &rt, &fl); if (err) goto error; df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; skb->local_df = 1; inet_get_local_port_range(&port_min, &port_max); src_port = vxlan_src_port(port_min, port_max, skb); err = vxlan_xmit_skb(net, vxlan_port->vs, rt, skb, fl.fl4_src, OVS_CB(skb)->tun_key->ipv4_dst, OVS_CB(skb)->tun_key->ipv4_tos, OVS_CB(skb)->tun_key->ipv4_ttl, df, src_port, dst_port, htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8)); if (err < 0) ip_rt_put(rt); error: return err; }
static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); struct ovs_key_ipv4_tunnel *tun_key; struct flowi4 fl; struct rtable *rt; int min_headroom; int tunnel_hlen; __be16 df; int err; if (unlikely(!OVS_CB(skb)->egress_tun_key)) { err = -EINVAL; goto error; } tun_key = OVS_CB(skb)->egress_tun_key; /* Route lookup */ memset(&fl, 0, sizeof(fl)); fl.daddr = tun_key->ipv4_dst; fl.saddr = tun_key->ipv4_src; fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos); fl.flowi4_mark = skb->mark; fl.flowi4_proto = IPPROTO_GRE; rt = ip_route_output_key(net, &fl); if (IS_ERR(rt)) return PTR_ERR(rt); tunnel_hlen = ip_gre_calc_hlen(tun_key->tun_flags); min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + tunnel_hlen + sizeof(struct iphdr) + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { int head_delta = SKB_DATA_ALIGN(min_headroom - skb_headroom(skb) + 16); err = pskb_expand_head(skb, max_t(int, head_delta, 0), 0, GFP_ATOMIC); if (unlikely(err)) goto err_free_rt; }
static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); struct rtable *rt; __be16 src_port; __be32 saddr; __be16 df; int err; if (unlikely(!OVS_CB(skb)->tun_key)) { err = -EINVAL; goto error; } /* Route lookup */ saddr = OVS_CB(skb)->tun_key->ipv4_src; rt = find_route(ovs_dp_get_net(vport->dp), &saddr, OVS_CB(skb)->tun_key->ipv4_dst, IPPROTO_UDP, OVS_CB(skb)->tun_key->ipv4_tos, skb->mark); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto error; } df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; skb->local_df = 1; src_port = udp_flow_src_port(net, skb, 0, 0, true); err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, saddr, OVS_CB(skb)->tun_key->ipv4_dst, OVS_CB(skb)->tun_key->ipv4_tos, OVS_CB(skb)->tun_key->ipv4_ttl, df, src_port, dst_port, htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8)); if (err < 0) ip_rt_put(rt); error: return err; }
/** * ovs_vport_receive - pass up received packet to the datapath for processing * * @vport: vport that received the packet * @skb: skb that was received * @tun_key: tunnel (if any) that carried packet * * Must be called with rcu_read_lock. The packet cannot be shared and * skb->data should point to the Ethernet header. */ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, struct ovs_key_ipv4_tunnel *tun_key) { struct pcpu_sw_netstats *stats; stats = this_cpu_ptr(vport->percpu_stats); u64_stats_update_begin(&stats->syncp); stats->rx_packets++; stats->rx_bytes += skb->len; u64_stats_update_end(&stats->syncp); OVS_CB(skb)->tun_key = tun_key; ovs_dp_process_received_packet(vport, skb); }
/** * ovs_vport_receive - pass up received packet to the datapath for processing * * @vport: vport that received the packet * @skb: skb that was received * @tun_key: tunnel (if any) that carried packet * * Must be called with rcu_read_lock. The packet cannot be shared and * skb->data should point to the Ethernet header. */ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, const struct ovs_tunnel_info *tun_info) { struct pcpu_sw_netstats *stats; struct sw_flow_key key; int error; stats = this_cpu_ptr(vport->percpu_stats); u64_stats_update_begin(&stats->syncp); stats->rx_packets++; stats->rx_bytes += skb->len + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); u64_stats_update_end(&stats->syncp); OVS_CB(skb)->input_vport = vport; OVS_CB(skb)->egress_tun_info = NULL; /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_key_extract(tun_info, skb, &key); if (unlikely(error)) { kfree_skb(skb); return; } ovs_dp_process_packet(skb, &key); }
static int vxlan_ext_gbp(struct sk_buff *skb) { const struct ovs_tunnel_info *tun_info; const struct ovs_vxlan_opts *opts; tun_info = OVS_CB(skb)->egress_tun_info; opts = tun_info->options; if (tun_info->tunnel.tun_flags & TUNNEL_VXLAN_OPT && tun_info->options_len >= sizeof(*opts)) return opts->gbp; else return 0; }
static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct ovs_tunnel_info *egress_tun_info) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); __be16 src_port; src_port = udp_flow_src_port(net, skb, 0, 0, true); return ovs_tunnel_get_egress_info(egress_tun_info, net, OVS_CB(skb)->egress_tun_info, IPPROTO_UDP, skb->mark, src_port, dst_port); }
static int stt_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct ovs_tunnel_info *egress_tun_info) { struct stt_port *stt_port = stt_vport(vport); struct net *net = ovs_dp_get_net(vport->dp); __be16 dport = inet_sk(stt_port->stt_sock->sock->sk)->inet_sport; __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); /* Get tp_src and tp_dst, refert to stt_build_header(). */ return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), OVS_CB(skb)->egress_tun_info, IPPROTO_TCP, skb->mark, sport, dport); }
/* Called with rcu_read_lock and BH disabled. */ static int gre_rcv(struct sk_buff *skb) { struct ovs_net *ovs_net; struct vport *vport; int hdr_len; struct iphdr *iph; struct ovs_key_ipv4_tunnel tun_key; __be16 gre_flags; u32 tnl_flags; __be64 key; bool is_gre64; if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN))) goto error; if (unlikely(!check_checksum(skb))) goto error; hdr_len = parse_header(ip_hdr(skb), &gre_flags, &key, &is_gre64); if (unlikely(hdr_len < 0)) goto error; ovs_net = net_generic(dev_net(skb->dev), ovs_net_id); if (is_gre64) vport = rcu_dereference(ovs_net->vport_net.gre64_vport); else vport = rcu_dereference(ovs_net->vport_net.gre_vport); if (unlikely(!vport)) goto error; if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN))) goto error; iph = ip_hdr(skb); tnl_flags = gre_flags_to_tunnel_flags(gre_flags, is_gre64); tnl_tun_key_init(&tun_key, iph, key, tnl_flags); OVS_CB(skb)->tun_key = &tun_key; __skb_pull(skb, hdr_len); skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN); ovs_tnl_rcv(vport, skb); return 0; error: kfree_skb(skb); return 0; }
static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct ovs_tunnel_info *egress_tun_info) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); __be16 src_port; int port_min; int port_max; inet_get_local_port_range(net, &port_min, &port_max); src_port = vxlan_src_port(port_min, port_max, skb); return ovs_tunnel_get_egress_info(egress_tun_info, net, OVS_CB(skb)->egress_tun_info, IPPROTO_UDP, skb->mark, src_port, dst_port); }
static struct sk_buff *__build_header(struct sk_buff *skb, int tunnel_hlen) { const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->egress_tun_key; struct tnl_ptk_info tpi; skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); if (IS_ERR(skb)) return NULL; tpi.flags = filter_tnl_flags(tun_key->tun_flags); tpi.proto = htons(ETH_P_TEB); tpi.key = be64_get_low32(tun_key->tun_id); tpi.seq = 0; gre_build_header(skb, &tpi, tunnel_hlen); return skb; }