diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 30 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 12 | ||||
-rw-r--r-- | net/ipv6/ip6_offload.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/Kconfig | 12 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 30 | ||||
-rw-r--r-- | net/ipv6/route.c | 6 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 6 | ||||
-rw-r--r-- | net/ipv6/udp.c | 67 |
8 files changed, 144 insertions, 22 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e73b3ebe5b9a..40c29712f32a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -240,6 +240,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { }, .use_oif_addrs_only = 0, .ignore_routes_with_linkdown = 0, + .accept_ra_prefix_route = 1, }; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { @@ -287,6 +288,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { }, .use_oif_addrs_only = 0, .ignore_routes_with_linkdown = 0, + .accept_ra_prefix_route = 1, }; /* Check if a valid qdisc is available */ @@ -2081,6 +2083,16 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) return addrconf_ifid_ieee1394(eui, dev); case ARPHRD_TUNNEL6: return addrconf_ifid_ip6tnl(eui, dev); + case ARPHRD_RAWIP: { + struct in6_addr lladdr; + + if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) + get_random_bytes(eui, 8); + else + memcpy(eui, lladdr.s6_addr + 8, 8); + + return 0; + } } return -1; } @@ -2463,8 +2475,11 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) flags |= RTF_EXPIRES; expires = jiffies_to_clock_t(rt_expires); } - addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, - dev, expires, flags); + if (dev->ip6_ptr->cnf.accept_ra_prefix_route) { + addrconf_prefix_route(&pinfo->prefix, + pinfo->prefix_len, + dev, expires, flags); + } } ip6_rt_put(rt); } @@ -3128,7 +3143,9 @@ static void addrconf_dev_config(struct net_device *dev) (dev->type != ARPHRD_IEEE802154) && (dev->type != ARPHRD_IEEE1394) && (dev->type != ARPHRD_TUNNEL6) && - (dev->type != ARPHRD_6LOWPAN)) { + (dev->type != ARPHRD_6LOWPAN) && + (dev->type != ARPHRD_RAWIP) && + (dev->type != ARPHRD_INFINIBAND)) { /* Alas, we support only Ethernet autoconfiguration. */ return; } @@ -5810,6 +5827,13 @@ static struct addrconf_sysctl_table .proc_handler = proc_dointvec, }, { + .procname = "accept_ra_prefix_route", + .data = &ipv6_devconf.accept_ra_prefix_route, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "stable_secret", .data = &ipv6_devconf.stable_secret, .maxlen = IPV6_MAX_STRLEN, diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 56528e9f3e01..d7c1ee7cf0e2 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -184,6 +184,11 @@ ipv4_connected: err = 0; if (IS_ERR(dst)) { err = PTR_ERR(dst); + /* Reset daddr and dport so that udp_v6_early_demux() + * fails to find this socket + */ + memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr)); + inet->inet_dport = 0; goto out; } @@ -968,9 +973,14 @@ void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, __u16 srcp, __u16 destp, int bucket) { const struct in6_addr *dest, *src; + __u8 state = sp->sk_state; dest = &sp->sk_v6_daddr; src = &sp->sk_v6_rcv_saddr; + + if (inet_sk(sp) && inet_sk(sp)->transparent) + state |= 0x80; + seq_printf(seq, "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", @@ -979,7 +989,7 @@ void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, + state, sk_wmem_alloc_get(sp), sk_rmem_alloc_get(sp), 0, 0L, 0, diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 9e2ea4ae840d..c612daad9e92 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -242,9 +242,6 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, /* flush if Traffic Class fields are different */ NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); NAPI_GRO_CB(p)->flush |= flush; - - /* Clear flush_id, there's really no concept of ID in IPv6. */ - NAPI_GRO_CB(p)->flush_id = 0; } NAPI_GRO_CB(skb)->flush |= flush; diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index e10a04c9cdc7..cf336d670f8b 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -135,6 +135,18 @@ config IP6_NF_IPTABLES if IP6_NF_IPTABLES +config IP6_NF_IPTABLES_128 + tristate "128 bit arithmetic for iptables matching" + depends on IP6_NF_IPTABLES + help + This enables 128 bit matching in ip6tables to help optimize cases + where there is no match required. ip6tables matching for ipv6 always + has a mask if an address is specified for match. Adding a check for + mask prior to that helps to improve performance as it avoids the + masked comparison. + + Note that this feature depends on the architecture. If unsure, say N. + # The simple matches. config IP6_NF_MATCH_AH tristate '"ah" match support' diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 22f39e00bef3..6fd784643d6e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -94,22 +94,26 @@ ip6_packet_match(const struct sk_buff *skb, { unsigned long ret; const struct ipv6hdr *ipv6 = ipv6_hdr(skb); +#if IS_ENABLED(IP6_NF_IPTABLES_128) + const __uint128_t *ulm1 = (const __uint128_t *)&ip6info->smsk; + const __uint128_t *ulm2 = (const __uint128_t *)&ip6info->dmsk; +#endif #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) - if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, - &ip6info->src), IP6T_INV_SRCIP) || - FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, - &ip6info->dst), IP6T_INV_DSTIP)) { - dprintf("Source or dest mismatch.\n"); -/* - dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, - ipinfo->smsk.s_addr, ipinfo->src.s_addr, - ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : ""); - dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr, - ipinfo->dmsk.s_addr, ipinfo->dst.s_addr, - ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/ - return false; +#if IS_ENABLED(IP6_NF_IPTABLES_128) + if (*ulm1 || *ulm2) +#endif + { + if (FWINV(ipv6_masked_addr_cmp + (&ipv6->saddr, &ip6info->smsk, &ip6info->src), + IP6T_INV_SRCIP) || + FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, + &ip6info->dst), + IP6T_INV_DSTIP)) { + dprintf("Source or dest mismatch.\n"); + return false; + } } ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index bf5b9551efb1..e367ce026db3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3212,6 +3212,10 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) { struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; int prefix; + struct net *net = arg->net; + + if (rt == net->ipv6.ip6_null_entry) + return 0; if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); @@ -3219,7 +3223,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) } else prefix = 0; - return rt6_fill_node(arg->net, + return rt6_fill_node(net, arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq, prefix, 0, NLM_F_MULTI); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7e29a31dd4f0..2bb5a6dc35e6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1723,6 +1723,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq; int rx_queue; int state; + __u8 state_seq = sp->sk_state; dest = &sp->sk_v6_daddr; src = &sp->sk_v6_rcv_saddr; @@ -1754,6 +1755,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) */ rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); + if (inet->transparent) + state_seq |= 0x80; + seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n", @@ -1762,7 +1766,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - state, + state_seq, tp->write_seq - tp->snd_una, rx_queue, timer_active, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3b0e22d20e83..329ae3ccfa35 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -45,6 +45,7 @@ #include <net/tcp_states.h> #include <net/ip6_checksum.h> #include <net/xfrm.h> +#include <net/inet_hashtables.h> #include <net/inet6_hashtables.h> #include <net/busy_poll.h> @@ -958,6 +959,71 @@ discard: return 0; } +static struct sock *__udp6_lib_demux_lookup(struct net *net, + __be16 loc_port, const struct in6_addr *loc_addr, + __be16 rmt_port, const struct in6_addr *rmt_addr, + int dif) +{ + struct sock *sk; + struct hlist_nulls_node *hnode; + unsigned short hnum = ntohs(loc_port); + unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum); + unsigned int slot2 = hash2 & udp_table.mask; + struct udp_hslot *hslot2 = &udp_table.hash2[slot2]; + + const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum); + + udp_portaddr_for_each_entry_rcu(sk, hnode, &hslot2->head) { + if (sk->sk_state == TCP_ESTABLISHED && + INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif)) + return sk; + /* Only check first socket in chain */ + break; + } + return NULL; +} + +static void udp_v6_early_demux(struct sk_buff *skb) +{ + struct net *net = dev_net(skb->dev); + const struct udphdr *uh; + struct sock *sk; + struct dst_entry *dst; + int dif = skb->dev->ifindex; + + if (!pskb_may_pull(skb, skb_transport_offset(skb) + + sizeof(struct udphdr))) + return; + + uh = udp_hdr(skb); + + if (skb->pkt_type == PACKET_HOST) + sk = __udp6_lib_demux_lookup(net, uh->dest, + &ipv6_hdr(skb)->daddr, + uh->source, &ipv6_hdr(skb)->saddr, + dif); + else + return; + + if (!sk || !atomic_inc_not_zero_hint(&sk->sk_refcnt, 2)) + return; + + skb->sk = sk; + skb->destructor = sock_efree; + dst = READ_ONCE(sk->sk_rx_dst); + + if (dst) + dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); + if (dst) { + if (dst->flags & DST_NOCACHE) { + if (likely(atomic_inc_not_zero(&dst->__refcnt))) + skb_dst_set(skb, dst); + } else { + skb_dst_set_noref(skb, dst); + } + } +} + static __inline__ int udpv6_rcv(struct sk_buff *skb) { return __udp6_lib_rcv(skb, &udp_table, IPPROTO_UDP); @@ -1466,6 +1532,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, #endif static const struct inet6_protocol udpv6_protocol = { + .early_demux = udp_v6_early_demux, .handler = udpv6_rcv, .err_handler = udpv6_err, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |