struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md, gfp_t flags) { struct metadata_dst *res; struct ip_tunnel_info *dst, *src; if (!md || md->u.tun_info.mode & IP_TUNNEL_INFO_TX) return NULL; res = metadata_dst_alloc(0, flags); if (!res) return NULL; dst = &res->u.tun_info; src = &md->u.tun_info; dst->key.tun_id = src->key.tun_id; if (src->mode & IP_TUNNEL_INFO_IPV6) memcpy(&dst->key.u.ipv6.dst, &src->key.u.ipv6.src, sizeof(struct in6_addr)); else dst->key.u.ipv4.dst = src->key.u.ipv4.src; dst->mode = src->mode | IP_TUNNEL_INFO_TX; return res; }
static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) { struct net *net = dev_net(skb->dev); struct metadata_dst *tun_dst = NULL; struct ip_tunnel_net *itn; const struct iphdr *iph; struct ip_tunnel *tunnel; if (tpi->proto == htons(ETH_P_TEB)) itn = net_generic(net, gre_tap_net_id); else itn = net_generic(net, ipgre_net_id); iph = ip_hdr(skb); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, iph->saddr, iph->daddr, tpi->key); if (tunnel) { skb_pop_mac_header(skb); if (tunnel->collect_md) { struct ip_tunnel_info *info; tun_dst = metadata_dst_alloc(0, GFP_ATOMIC); if (!tun_dst) return PACKET_REJECT; info = &tun_dst->u.tun_info; info->key.ipv4_src = iph->saddr; info->key.ipv4_dst = iph->daddr; info->key.ipv4_tos = iph->tos; info->key.ipv4_ttl = iph->ttl; info->mode = IP_TUNNEL_INFO_RX; info->key.tun_flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY); info->key.tun_id = key_to_tunnel_id(tpi->key); info->key.tp_src = 0; info->key.tp_dst = 0; } ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); return PACKET_RCVD; } return PACKET_REJECT; }
int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, u32 cmsg_port_id, struct nfp_port *port, struct net_device *pf_netdev) { struct nfp_repr *repr = netdev_priv(netdev); struct nfp_net *nn = netdev_priv(pf_netdev); u32 repr_cap = nn->tlv_caps.repr_cap; int err; nfp_repr_set_lockdep_class(netdev); repr->port = port; repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL); if (!repr->dst) return -ENOMEM; repr->dst->u.port_info.port_id = cmsg_port_id; repr->dst->u.port_info.lower_dev = pf_netdev; netdev->netdev_ops = &nfp_repr_netdev_ops; netdev->ethtool_ops = &nfp_port_ethtool_ops; netdev->max_mtu = pf_netdev->max_mtu; /* Set features the lower device can support with representors */ if (repr_cap & NFP_NET_CFG_CTRL_LIVE_ADDR) netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; netdev->hw_features = NETIF_F_HIGHDMA; if (repr_cap & NFP_NET_CFG_CTRL_RXCSUM_ANY) netdev->hw_features |= NETIF_F_RXCSUM; if (repr_cap & NFP_NET_CFG_CTRL_TXCSUM) netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; if (repr_cap & NFP_NET_CFG_CTRL_GATHER) netdev->hw_features |= NETIF_F_SG; if ((repr_cap & NFP_NET_CFG_CTRL_LSO && nn->fw_ver.major > 2) || repr_cap & NFP_NET_CFG_CTRL_LSO2) netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; if (repr_cap & NFP_NET_CFG_CTRL_RSS_ANY) netdev->hw_features |= NETIF_F_RXHASH; if (repr_cap & NFP_NET_CFG_CTRL_VXLAN) { if (repr_cap & NFP_NET_CFG_CTRL_LSO) netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; } if (repr_cap & NFP_NET_CFG_CTRL_NVGRE) { if (repr_cap & NFP_NET_CFG_CTRL_LSO) netdev->hw_features |= NETIF_F_GSO_GRE; } if (repr_cap & (NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE)) netdev->hw_enc_features = netdev->hw_features; netdev->vlan_features = netdev->hw_features; if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN) netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN) { if (repr_cap & NFP_NET_CFG_CTRL_LSO2) netdev_warn(netdev, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); else netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; } if (repr_cap & NFP_NET_CFG_CTRL_CTAG_FILTER) netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; netdev->features = netdev->hw_features; /* Advertise but disable TSO by default. */ netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); netdev->gso_max_segs = NFP_NET_LSO_MAX_SEGS; netdev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL; netdev->features |= NETIF_F_LLTX; if (nfp_app_has_tc(app)) { netdev->features |= NETIF_F_HW_TC; netdev->hw_features |= NETIF_F_HW_TC; } err = nfp_app_repr_init(app, netdev); if (err) goto err_clean; err = register_netdev(netdev); if (err) goto err_repr_clean; return 0; err_repr_clean: nfp_app_repr_clean(app, netdev); err_clean: dst_release((struct dst_entry *)repr->dst); return err; }