Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

====================
Netfilter/IPVS updates for net-next

The following patchset container Netfilter/IPVS update for net-next:

1) Add UDP tunnel support for ICMP errors in IPVS.

Julian Anastasov says:

This patchset is a followup to the commit that adds UDP/GUE tunnel:
"ipvs: allow tunneling with gue encapsulation".

What we do is to put tunnel real servers in hash table (patch 1),
add function to lookup tunnels (patch 2) and use it to strip the
embedded tunnel headers from ICMP errors (patch 3).

2) Extend xt_owner to match for supplementary groups, from
   Lukasz Pawelczyk.

3) Remove unused oif field in flow_offload_tuple object, from
   Taehee Yoo.

4) Release basechain counters from workqueue to skip synchronize_rcu()
   call. From Florian Westphal.

5) Replace skb_make_writable() by skb_ensure_writable(). Patchset
   from Florian Westphal.

6) Checksum support for gue encapsulation in IPVS, from Jacky Hu.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 1, 2019
2 parents 0462eaa + 29930e3 commit c1e9e01
Show file tree
Hide file tree
Showing 37 changed files with 389 additions and 149 deletions.
5 changes: 0 additions & 5 deletions include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,6 @@ int compat_nf_getsockopt(struct sock *sk, u_int8_t pf, int optval,
char __user *opt, int *len);
#endif

/* Call this before modifying an existing packet: ensures it is
modifiable and linear to the point you care about (writable_len).
Returns true or false. */
int skb_make_writable(struct sk_buff *skb, unsigned int writable_len);

struct flowi;
struct nf_queue_entry;

Expand Down
8 changes: 8 additions & 0 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ struct ip_vs_dest_user_kern {

u16 tun_type; /* tunnel type */
__be16 tun_port; /* tunnel port */
u16 tun_flags; /* tunnel flags */
};


Expand Down Expand Up @@ -665,6 +666,7 @@ struct ip_vs_dest {
atomic_t last_weight; /* server latest weight */
__u16 tun_type; /* tunnel type */
__be16 tun_port; /* tunnel port */
__u16 tun_flags; /* tunnel flags */

refcount_t refcnt; /* reference counter */
struct ip_vs_stats stats; /* statistics */
Expand Down Expand Up @@ -1404,6 +1406,9 @@ bool ip_vs_has_real_service(struct netns_ipvs *ipvs, int af, __u16 protocol,
struct ip_vs_dest *
ip_vs_find_real_service(struct netns_ipvs *ipvs, int af, __u16 protocol,
const union nf_inet_addr *daddr, __be16 dport);
struct ip_vs_dest *ip_vs_find_tunnel(struct netns_ipvs *ipvs, int af,
const union nf_inet_addr *daddr,
__be16 tun_port);

int ip_vs_use_count_inc(void);
void ip_vs_use_count_dec(void);
Expand Down Expand Up @@ -1497,6 +1502,9 @@ static inline int ip_vs_todrop(struct netns_ipvs *ipvs)
static inline int ip_vs_todrop(struct netns_ipvs *ipvs) { return 0; }
#endif

#define IP_VS_DFWD_METHOD(dest) (atomic_read(&(dest)->conn_flags) & \
IP_VS_CONN_F_FWD_MASK)

/* ip_vs_fwd_tag returns the forwarding tag of the connection */
#define IP_VS_FWD_METHOD(cp) (cp->flags & IP_VS_CONN_F_FWD_MASK)

Expand Down
2 changes: 0 additions & 2 deletions include/net/netfilter/nf_flow_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ struct flow_offload_tuple {
u8 l4proto;
u8 dir;

int oifidx;

u16 mtu;

struct dst_entry *dst_cache;
Expand Down
7 changes: 7 additions & 0 deletions include/uapi/linux/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ enum {
IP_VS_CONN_F_TUNNEL_TYPE_MAX,
};

/* Tunnel encapsulation flags */
#define IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM (0)
#define IP_VS_TUNNEL_ENCAP_FLAG_CSUM (1 << 0)
#define IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM (1 << 1)

/*
* The struct ip_vs_service_user and struct ip_vs_dest_user are
* used to set IPVS rules through setsockopt.
Expand Down Expand Up @@ -403,6 +408,8 @@ enum {

IPVS_DEST_ATTR_TUN_PORT, /* tunnel port */

IPVS_DEST_ATTR_TUN_FLAGS, /* tunnel flags */

__IPVS_DEST_ATTR_MAX,
};

Expand Down
7 changes: 4 additions & 3 deletions include/uapi/linux/netfilter/xt_owner.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
#include <linux/types.h>

enum {
XT_OWNER_UID = 1 << 0,
XT_OWNER_GID = 1 << 1,
XT_OWNER_SOCKET = 1 << 2,
XT_OWNER_UID = 1 << 0,
XT_OWNER_GID = 1 << 1,
XT_OWNER_SOCKET = 1 << 2,
XT_OWNER_SUPPL_GROUPS = 1 << 3,
};

struct xt_owner_match_info {
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/netfilter/ebt_dnat.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
const struct ebt_nat_info *info = par->targinfo;
struct net_device *dev;

if (!skb_make_writable(skb, 0))
if (skb_ensure_writable(skb, ETH_ALEN))
return EBT_DROP;

ether_addr_copy(eth_hdr(skb)->h_dest, info->mac);
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/netfilter/ebt_redirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct ebt_redirect_info *info = par->targinfo;

if (!skb_make_writable(skb, 0))
if (skb_ensure_writable(skb, ETH_ALEN))
return EBT_DROP;

if (xt_hooknum(par) != NF_BR_BROUTING)
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/netfilter/ebt_snat.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct ebt_nat_info *info = par->targinfo;

if (!skb_make_writable(skb, 0))
if (skb_ensure_writable(skb, ETH_ALEN * 2))
return EBT_DROP;

ether_addr_copy(eth_hdr(skb)->h_source, info->mac);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/netfilter/arpt_mangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
unsigned char *arpptr;
int pln, hln;

if (!skb_make_writable(skb, skb->len))
if (skb_ensure_writable(skb, skb->len))
return NF_DROP;

arp = arp_hdr(skb);
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/netfilter/ipt_ECN.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ set_ect_ip(struct sk_buff *skb, const struct ipt_ECN_info *einfo)

if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
__u8 oldtos;
if (!skb_make_writable(skb, sizeof(struct iphdr)))
if (skb_ensure_writable(skb, sizeof(struct iphdr)))
return false;
iph = ip_hdr(skb);
oldtos = iph->tos;
Expand Down Expand Up @@ -61,7 +61,7 @@ set_ect_tcp(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
tcph->cwr == einfo->proto.tcp.cwr))
return true;

if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
if (skb_ensure_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
return false;
tcph = (void *)ip_hdr(skb) + ip_hdrlen(skb);

Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/netfilter/nf_nat_h323.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static int set_addr(struct sk_buff *skb, unsigned int protoff,
net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_udp_packet error\n");
return -1;
}
/* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
/* nf_nat_mangle_udp_packet uses skb_ensure_writable() to copy
* or pull everything in a linear buffer, so we can safely
* use the skb pointers now */
*data = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/netfilter/nf_nat_snmp_basic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
return NF_DROP;
}

if (!skb_make_writable(skb, skb->len)) {
if (skb_ensure_writable(skb, skb->len)) {
nf_ct_helper_log(skb, ct, "cannot mangle packet");
return NF_DROP;
}
Expand Down
22 changes: 0 additions & 22 deletions net/netfilter/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,28 +536,6 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
}
EXPORT_SYMBOL(nf_hook_slow);


int skb_make_writable(struct sk_buff *skb, unsigned int writable_len)
{
if (writable_len > skb->len)
return 0;

/* Not exclusive use of packet? Must copy. */
if (!skb_cloned(skb)) {
if (writable_len <= skb_headlen(skb))
return 1;
} else if (skb_clone_writable(skb, writable_len))
return 1;

if (writable_len <= skb_headlen(skb))
writable_len = 0;
else
writable_len -= skb_headlen(skb);

return !!__pskb_pull_tail(skb, writable_len);
}
EXPORT_SYMBOL(skb_make_writable);

/* This needs to be compiled in any case to avoid dependencies between the
* nfnetlink_queue code and nf_conntrack.
*/
Expand Down
4 changes: 2 additions & 2 deletions net/netfilter/ipvs/ip_vs_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
struct tcphdr *th;
__u32 seq;

if (!skb_make_writable(skb, tcp_offset + sizeof(*th)))
if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
return 0;

th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
Expand Down Expand Up @@ -440,7 +440,7 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb,
struct tcphdr *th;
__u32 seq;

if (!skb_make_writable(skb, tcp_offset + sizeof(*th)))
if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
return 0;

th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
Expand Down
72 changes: 70 additions & 2 deletions net/netfilter/ipvs/ip_vs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <net/tcp.h>
#include <net/udp.h>
#include <net/icmp.h> /* for icmp_send */
#include <net/gue.h>
#include <net/route.h>
#include <net/ip6_checksum.h>
#include <net/netns/generic.h> /* net_generic() */
Expand Down Expand Up @@ -897,7 +898,7 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol ||
IPPROTO_SCTP == protocol)
offset += 2 * sizeof(__u16);
if (!skb_make_writable(skb, offset))
if (skb_ensure_writable(skb, offset))
goto out;

#ifdef CONFIG_IP_VS_IPV6
Expand Down Expand Up @@ -1287,7 +1288,7 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,

IP_VS_DBG_PKT(11, af, pp, skb, iph->off, "Outgoing packet");

if (!skb_make_writable(skb, iph->len))
if (skb_ensure_writable(skb, iph->len))
goto drop;

/* mangle the packet */
Expand Down Expand Up @@ -1579,6 +1580,41 @@ ip_vs_try_to_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
return 1;
}

/* Check the UDP tunnel and return its header length */
static int ipvs_udp_decap(struct netns_ipvs *ipvs, struct sk_buff *skb,
unsigned int offset, __u16 af,
const union nf_inet_addr *daddr, __u8 *proto)
{
struct udphdr _udph, *udph;
struct ip_vs_dest *dest;

udph = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
if (!udph)
goto unk;
offset += sizeof(struct udphdr);
dest = ip_vs_find_tunnel(ipvs, af, daddr, udph->dest);
if (!dest)
goto unk;
if (dest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
struct guehdr _gueh, *gueh;

gueh = skb_header_pointer(skb, offset, sizeof(_gueh), &_gueh);
if (!gueh)
goto unk;
if (gueh->control != 0 || gueh->version != 0)
goto unk;
/* Later we can support also IPPROTO_IPV6 */
if (gueh->proto_ctype != IPPROTO_IPIP)
goto unk;
*proto = gueh->proto_ctype;
return sizeof(struct udphdr) + sizeof(struct guehdr) +
(gueh->hlen << 2);
}

unk:
return 0;
}

/*
* Handle ICMP messages in the outside-to-inside direction (incoming).
* Find any that might be relevant, check against existing connections,
Expand All @@ -1598,6 +1634,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
struct ip_vs_proto_data *pd;
unsigned int offset, offset2, ihl, verdict;
bool ipip, new_cp = false;
union nf_inet_addr *raddr;

*related = 1;

Expand Down Expand Up @@ -1636,20 +1673,51 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
if (cih == NULL)
return NF_ACCEPT; /* The packet looks wrong, ignore */
raddr = (union nf_inet_addr *)&cih->daddr;

/* Special case for errors for IPIP packets */
ipip = false;
if (cih->protocol == IPPROTO_IPIP) {
struct ip_vs_dest *dest;

if (unlikely(cih->frag_off & htons(IP_OFFSET)))
return NF_ACCEPT;
/* Error for our IPIP must arrive at LOCAL_IN */
if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
return NF_ACCEPT;
dest = ip_vs_find_tunnel(ipvs, AF_INET, raddr, 0);
/* Only for known tunnel */
if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
return NF_ACCEPT;
offset += cih->ihl * 4;
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
if (cih == NULL)
return NF_ACCEPT; /* The packet looks wrong, ignore */
ipip = true;
} else if (cih->protocol == IPPROTO_UDP && /* Can be UDP encap */
/* Error for our tunnel must arrive at LOCAL_IN */
(skb_rtable(skb)->rt_flags & RTCF_LOCAL)) {
__u8 iproto;
int ulen;

/* Non-first fragment has no UDP header */
if (unlikely(cih->frag_off & htons(IP_OFFSET)))
return NF_ACCEPT;
offset2 = offset + cih->ihl * 4;
ulen = ipvs_udp_decap(ipvs, skb, offset2, AF_INET, raddr,
&iproto);
if (ulen > 0) {
/* Skip IP and UDP tunnel headers */
offset = offset2 + ulen;
/* Now we should be at the original IP header */
cih = skb_header_pointer(skb, offset, sizeof(_ciph),
&_ciph);
if (cih && cih->version == 4 && cih->ihl >= 5 &&
iproto == IPPROTO_IPIP)
ipip = true;
else
return NF_ACCEPT;
}
}

pd = ip_vs_proto_data_get(ipvs, cih->protocol);
Expand Down
Loading

0 comments on commit c1e9e01

Please sign in to comment.