Release 4.11 net/openvswitch/actions.c
/*
* Copyright (c) 2007-2014 Nicira, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/openvswitch.h>
#include <linux/netfilter_ipv6.h>
#include <linux/sctp.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/in6.h>
#include <linux/if_arp.h>
#include <linux/if_vlan.h>
#include <net/dst.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/checksum.h>
#include <net/dsfield.h>
#include <net/mpls.h>
#include <net/sctp/checksum.h>
#include "datapath.h"
#include "flow.h"
#include "conntrack.h"
#include "vport.h"
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key,
const struct nlattr *attr, int len);
struct deferred_action {
struct sk_buff *skb;
const struct nlattr *actions;
/* Store pkt_key clone when creating deferred action. */
struct sw_flow_key pkt_key;
};
#define MAX_L2_LEN (VLAN_ETH_HLEN + 3 * MPLS_HLEN)
struct ovs_frag_data {
unsigned long dst;
struct vport *vport;
struct ovs_skb_cb cb;
__be16 inner_protocol;
u16 network_offset; /* valid only for MPLS */
u16 vlan_tci;
__be16 vlan_proto;
unsigned int l2_len;
u8 mac_proto;
u8 l2_data[MAX_L2_LEN];
};
static DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage);
#define DEFERRED_ACTION_FIFO_SIZE 10
#define OVS_RECURSION_LIMIT 5
#define OVS_DEFERRED_ACTION_THRESHOLD (OVS_RECURSION_LIMIT - 2)
struct action_fifo {
int head;
int tail;
/* Deferred action fifo queue storage. */
struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE];
};
struct recirc_keys {
struct sw_flow_key key[OVS_DEFERRED_ACTION_THRESHOLD];
};
static struct action_fifo __percpu *action_fifos;
static struct recirc_keys __percpu *recirc_keys;
static DEFINE_PER_CPU(int, exec_actions_level);
static void action_fifo_init(struct action_fifo *fifo)
{
fifo->head = 0;
fifo->tail = 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andy Zhou | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
static bool action_fifo_is_empty(const struct action_fifo *fifo)
{
return (fifo->head == fifo->tail);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andy Zhou | 22 | 95.65% | 1 | 50.00% |
Thomas Graf | 1 | 4.35% | 1 | 50.00% |
Total | 23 | 100.00% | 2 | 100.00% |
static struct deferred_action *action_fifo_get(struct action_fifo *fifo)
{
if (action_fifo_is_empty(fifo))
return NULL;
return &fifo->fifo[fifo->tail++];
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andy Zhou | 35 | 100.00% | 1 | 100.00% |
Total | 35 | 100.00% | 1 | 100.00% |
static struct deferred_action *action_fifo_put(struct action_fifo *fifo)
{
if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1)
return NULL;
return &fifo->fifo[fifo->head++];
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andy Zhou | 38 | 100.00% | 1 | 100.00% |
Total | 38 | 100.00% | 1 | 100.00% |
/* Return true if fifo is not full */
static struct deferred_action *add_deferred_actions(struct sk_buff *skb,
const struct sw_flow_key *key,
const struct nlattr *attr)
{
struct action_fifo *fifo;
struct deferred_action *da;
fifo = this_cpu_ptr(action_fifos);
da = action_fifo_put(fifo);
if (da) {
da->skb = skb;
da->actions = attr;
da->pkt_key = *key;
}
return da;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andy Zhou | 76 | 98.70% | 1 | 50.00% |
Thomas Graf | 1 | 1.30% | 1 | 50.00% |
Total | 77 | 100.00% | 2 | 100.00% |
static void invalidate_flow_key(struct sw_flow_key *key)
{
key->mac_proto |= SW_FLOW_KEY_INVALID;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Pravin B Shelar | 14 | 82.35% | 1 | 50.00% |
Jiri Benc | 3 | 17.65% | 1 | 50.00% |
Total | 17 | 100.00% | 2 | 100.00% |
static bool is_flow_key_valid(const struct sw_flow_key *key)
{
return !(key->mac_proto & SW_FLOW_KEY_INVALID);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Pravin B Shelar | 17 | 77.27% | 1 | 50.00% |
Jiri Benc | 5 | 22.73% | 1 | 50.00% |
Total | 22 | 100.00% | 2 | 100.00% |
static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr,
__be16 ethertype)
{
if (skb->ip_summed == CHECKSUM_COMPLETE) {
__be16 diff[] = { ~(hdr->h_proto), ethertype };
skb->csum = ~csum_partial((char *)diff, sizeof(diff),
~skb->csum);
}
hdr->h_proto = ethertype;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Simon Horman | 74 | 100.00% | 1 | 100.00% |
Total | 74 | 100.00% | 1 | 100.00% |
static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
const struct ovs_action_push_mpls *mpls)
{
struct mpls_shim_hdr *new_mpls_lse;
/* Networking stack do not allow simultaneous Tunnel and MPLS GSO. */
if (skb->encapsulation)
return -ENOTSUPP;
if (skb_cow_head(skb, MPLS_HLEN) < 0)
return -ENOMEM;
if (!skb->inner_protocol) {
skb_set_inner_network_header(skb, skb->mac_len);
skb_set_inner_protocol(skb, skb->protocol);
}
skb_push(skb, MPLS_HLEN);
memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb),
skb->mac_len);
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb->mac_len);
new_mpls_lse = mpls_hdr(skb);
new_mpls_lse->label_stack_entry = mpls->mpls_lse;
skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN);
if (ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET)
update_ethertype(skb, eth_hdr(skb), mpls->mpls_ethertype);
skb->protocol = mpls->mpls_ethertype;
invalidate_flow_key(key);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Simon Horman | 122 | 66.67% | 2 | 28.57% |
David Ahern | 36 | 19.67% | 1 | 14.29% |
Jiri Benc | 14 | 7.65% | 2 | 28.57% |
Pravin B Shelar | 10 | 5.46% | 1 | 14.29% |
Daniel Borkmann | 1 | 0.55% | 1 | 14.29% |
Total | 183 | 100.00% | 7 | 100.00% |
static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
const __be16 ethertype)
{
int err;
err = skb_ensure_writable(skb, skb->mac_len + MPLS_HLEN);
if (unlikely(err))
return err;
skb_postpull_rcsum(skb, mpls_hdr(skb), MPLS_HLEN);
memmove(skb_mac_header(skb) + MPLS_HLEN, skb_mac_header(skb),
skb->mac_len);
__skb_pull(skb, MPLS_HLEN);
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb->mac_len);
if (ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET) {
struct ethhdr *hdr;
/* mpls_hdr() is used to locate the ethertype field correctly in the
* presence of VLAN tags.
*/
hdr = (struct ethhdr *)((void *)mpls_hdr(skb) - ETH_HLEN);
update_ethertype(skb, hdr, ethertype);
}
if (eth_p_mpls(skb->protocol))
skb->protocol = ethertype;
invalidate_flow_key(key);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Simon Horman | 123 | 73.65% | 2 | 25.00% |
Jiri Benc | 23 | 13.77% | 2 | 25.00% |
Pravin B Shelar | 10 | 5.99% | 1 | 12.50% |
David Ahern | 9 | 5.39% | 1 | 12.50% |
Jiri Pirko | 2 | 1.20% | 2 | 25.00% |
Total | 167 | 100.00% | 8 | 100.00% |
static int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key,
const __be32 *mpls_lse, const __be32 *mask)
{
struct mpls_shim_hdr *stack;
__be32 lse;
int err;
err = skb_ensure_writable(skb, skb->mac_len + MPLS_HLEN);
if (unlikely(err))
return err;
stack = mpls_hdr(skb);
lse = OVS_MASKED(stack->label_stack_entry, *mpls_lse, *mask);
if (skb->ip_summed == CHECKSUM_COMPLETE) {
__be32 diff[] = { ~(stack->label_stack_entry), lse };
skb->csum = ~csum_partial((char *)diff, sizeof(diff),
~skb->csum);
}
stack->label_stack_entry = lse;
flow_key->mpls.top_lse = lse;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Simon Horman | 102 | 68.92% | 1 | 16.67% |
Jarno Rajahalme | 25 | 16.89% | 1 | 16.67% |
Pravin B Shelar | 10 | 6.76% | 1 | 16.67% |
Jiri Benc | 9 | 6.08% | 1 | 16.67% |
Jiri Pirko | 1 | 0.68% | 1 | 16.67% |
Joe Stringer | 1 | 0.68% | 1 | 16.67% |
Total | 148 | 100.00% | 6 | 100.00% |
static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
{
int err;
err = skb_vlan_pop(skb);
if (skb_vlan_tag_present(skb)) {
invalidate_flow_key(key);
} else {
key->eth.vlan.tci = 0;
key->eth.vlan.tpid = 0;
}
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jesse Gross | 30 | 45.45% | 1 | 20.00% |
Eric Garver | 16 | 24.24% | 1 | 20.00% |
Pravin B Shelar | 13 | 19.70% | 1 | 20.00% |
Jiri Pirko | 7 | 10.61% | 2 | 40.00% |
Total | 66 | 100.00% | 5 | 100.00% |
static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
const struct ovs_action_push_vlan *vlan)
{
if (skb_vlan_tag_present(skb)) {
invalidate_flow_key(key);
} else {
key->eth.vlan.tci = vlan->vlan_tci;
key->eth.vlan.tpid = vlan->vlan_tpid;
}
return skb_vlan_push(skb, vlan->vlan_tpid,
ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jesse Gross | 37 | 44.58% | 1 | 16.67% |
Pravin B Shelar | 21 | 25.30% | 1 | 16.67% |
Eric Garver | 18 | 21.69% | 1 | 16.67% |
Patrick McHardy | 4 | 4.82% | 1 | 16.67% |
Jiri Pirko | 3 | 3.61% | 2 | 33.33% |
Total | 83 | 100.00% | 6 | 100.00% |
/* 'src' is already properly masked. */
static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_)
{
u16 *dst = (u16 *)dst_;
const u16 *src = (const u16 *)src_;
const u16 *mask = (const u16 *)mask_;
OVS_SET_MASKED(dst[0], src[0], mask[0]);
OVS_SET_MASKED(dst[1], src[1], mask[1]);
OVS_SET_MASKED(dst[2], src[2], mask[2]);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jarno Rajahalme | 105 | 97.22% | 1 | 50.00% |
Joe Stringer | 3 | 2.78% | 1 | 50.00% |
Total | 108 | 100.00% | 2 | 100.00% |
static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
const struct ovs_key_ethernet *key,
const struct ovs_key_ethernet *mask)
{
int err;
err = skb_ensure_writable(skb, ETH_HLEN);
if (unlikely(err))
return err;
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
ether_addr_copy_masked(eth_hdr(skb)->h_source, key->eth_src,
mask->eth_src);
ether_addr_copy_masked(eth_hdr(skb)->h_dest, key->eth_dst,
mask->eth_dst);
skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
ether_addr_copy(flow_key->eth.src, eth_hdr(skb)->h_source);
ether_addr_copy(flow_key->eth.dst, eth_hdr(skb)->h_dest);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jesse Gross | 64 | 42.95% | 1 | 16.67% |
Pravin B Shelar | 52 | 34.90% | 2 | 33.33% |
Jarno Rajahalme | 31 | 20.81% | 1 | 16.67% |
Jiri Pirko | 1 | 0.67% | 1 | 16.67% |
Daniel Borkmann | 1 | 0.67% | 1 | 16.67% |
Total | 149 | 100.00% | 6 | 100.00% |
/* pop_eth does not support VLAN packets as this action is never called
* for them.
*/
static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)
{
skb_pull_rcsum(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);
/* safe right before invalidate_flow_key */
key->mac_proto = MAC_PROTO_NONE;
invalidate_flow_key(key);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Benc | 48 | 100.00% | 1 | 100.00% |
Total | 48 | 100.00% | 1 | 100.00% |
static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
const struct ovs_action_push_eth *ethh)
{
struct ethhdr *hdr;
/* Add the new Ethernet header */
if (skb_cow_head(skb, ETH_HLEN) < 0)
return -ENOMEM;
skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb_reset_mac_len(skb);
hdr = eth_hdr(skb);
ether_addr_copy(hdr->h_source, ethh->addresses.eth_src);
ether_addr_copy(hdr->h_dest, ethh->addresses.eth_dst);
hdr->h_proto = skb->protocol;
skb_postpush_rcsum(skb, hdr, ETH_HLEN);
/* safe right before invalidate_flow_key */
key->mac_proto = MAC_PROTO_ETHERNET;
invalidate_flow_key(key);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jiri Benc | 125 | 100.00% | 1 | 100.00% |
Total | 125 | 100.00% | 1 | 100.00% |
static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
__be32 addr, __be32 new_addr)
{
int transport_len = skb->len - skb_transport_offset(skb);
if (nh->frag_off & htons(IP_OFFSET))
return;
if (nh->protocol == IPPROTO_TCP) {
if (likely(transport_len >= sizeof(struct tcphdr)))
inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
addr, new_addr, true);
} else if (nh->protocol == IPPROTO_UDP) {
if (likely(transport_len >= sizeof(struct udphdr))) {
struct udphdr *uh = udp_hdr(skb);
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
inet_proto_csum_replace4(&uh->check, skb,
addr, new_addr, true);
if (!uh->check)
uh->check = CSUM_MANGLED_0;
}
}
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jesse Gross | 151 | 90.42% | 2 | 50.00% |
Glenn Griffin | 14 | 8.38% | 1 | 25.00% |
Tom Herbert | 2 | 1.20% | 1 | 25.00% |
Total | 167 | 100.00% | 4 | 100.00% |
static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
__be32 *addr, __be32 new_addr)
{
update_ip_l4_checksum(skb, nh, *addr, new_addr);
csum_replace4(&nh->check, *addr, new_addr);
skb_clear_hash(skb);
*addr = new_addr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Glenn Griffin | 34 | 58.62% | 1 | 33.33% |
Jesse Gross | 21 | 36.21% | 1 | 33.33% |
Tom Herbert | 3 | 5.17% | 1 | 33.33% |
Total | 58 | 100.00% | 3 | 100.00% |
static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
__be32 addr[4], const __be32 new_addr[4])
{
int transport_len = skb->len - skb_transport_offset(skb);
if (l4_proto == NEXTHDR_TCP) {
if (likely(transport_len >= sizeof(struct tcphdr)))
inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
addr, new_addr, true);
} else if (l4_proto == NEXTHDR_UDP) {
if (likely(transport_len >= sizeof(struct udphdr))) {
struct udphdr *uh = udp_hdr(skb);
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
inet_proto_csum_replace16(&uh->check, skb,
addr, new_addr, true);
if (!uh->check)
uh->check = CSUM_MANGLED_0;
}
}
} else if (l4_proto == NEXTHDR_ICMP) {
if (likely(transport_len >= sizeof(struct icmp6hdr)))
inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum,
skb, addr, new_addr, true);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ansis Atteka | 152 | 77.16% | 1 | 33.33% |
Jesse Gross | 42 | 21.32% | 1 | 33.33% |
Tom Herbert | 3 | 1.52% | 1 | 33.33% |
Total | 197 | 100.00% | 3 | 100.00% |
static void mask_ipv6_addr(const __be32 old[4], const __be32 addr[4],
const __be32 mask[4], __be32 masked[4])
{
masked[0] = OVS_MASKED(old[0], addr[0], mask[0]);
masked[1] = OVS_MASKED(old[1], addr[1], mask[1]);
masked[2] = OVS_MASKED(old[2], addr[2], mask[2]);
masked[3] = OVS_MASKED(old[3], addr[3], mask[3]);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jarno Rajahalme | 85 | 68.00% | 1 | 25.00% |
Ansis Atteka | 34 | 27.20% | 1 | 25.00% |
Joe Stringer | 4 | 3.20% | 1 | 25.00% |
Tom Herbert | 2 | 1.60% | 1 | 25.00% |
Total | 125 | 100.00% | 4 | 100.00% |
static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto,
__be32 addr[4], const __be32 new_addr[4],
bool recalculate_csum)
{
if (recalculate_csum)
update_ipv6_checksum(skb, l4_proto, addr, new_addr);
skb_clear_hash(skb);
memcpy(addr, new_addr, sizeof(__be32[4]));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jarno Rajahalme | 58 | 89.23% | 1 | 50.00% |
Ansis Atteka | 7 | 10.77% | 1 | 50.00% |
Total | 65 | 100.00% | 2 | 100.00% |
static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl, u32 mask)
{
/* Bits 21-24 are always unmasked, so this retains their values. */
OVS_SET_MASKED(nh->flow_lbl[0], (u8)(fl >> 16), (u8)(mask >> 16));
OVS_SET_MASKED(nh->flow_lbl[1], (u8)(fl >> 8), (u8)(mask >> 8));
OVS_SET_MASKED(nh->flow_lbl[2], (u8)fl, (u8)mask);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jarno Rajahalme | 49 | 52.13% | 1 | 33.33% |
Ansis Atteka | 42 | 44.68% | 1 | 33.33% |
Joe Stringer | 3 | 3.19% | 1 | 33.33% |
Total | 94 | 100.00% | 3 | 100.00% |
static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl,
u8 mask)
{
new_ttl = OVS_MASKED(nh->ttl, new_ttl, mask);
csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8));
nh->ttl = new_ttl;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jesse Gross | 49 | 75.38% | 1 | 33.33% |
Jarno Rajahalme | 15 | 23.08% | 1 | 33.33% |
Joe Stringer | 1 | 1.54% | 1 | 33.33% |
Total | 65 | 100.00% | 3 | 100.00% |
static int set_ipv4(struct sk_buff *skb, struct sw_flow_key *flow_key,
const struct ovs_key_ipv4 *key,
const struct ovs_key_ipv4 *mask)
{
struct iphdr *nh;
__be32 new_addr;
int err;
err = skb_ensure_writable(skb, skb_network_offset(skb) +
sizeof(struct iphdr));
if (unlikely(err))
return err;
nh = ip_hdr(skb);
/* Setting an IP addresses is typically only a side effect of
* matching on them in the current userspace implementation, so it
* makes sense to check if the value actually changed.
*/
if (mask->ipv4_src) {
new_addr = OVS_MASKED(nh->saddr, key->ipv4_src, mask->ipv4_src);
if (unlikely(new_addr != nh->saddr)) {
set_ip_addr(skb, nh, &nh->saddr, new_addr);
flow_key->ipv4.addr.src = new_addr;
}
}
if (mask->ipv4_dst) {
new_addr = OVS_MASKED(nh->daddr, key->ipv4_dst, mask->ipv4_dst);
if (unlikely(new_addr != nh->daddr)) {
set_ip_addr(skb, nh, &nh->daddr, new_addr);
flow_key->ipv4.addr.dst = new_addr;
}
}
if (mask->ipv4_tos) {
ipv4_change_dsfield(nh, ~mask->ipv4_tos, key->ipv4_tos);
flow_key->ip.tos = nh->tos;
}
if (mask->ipv4_ttl) {
set_ip_ttl(skb, nh, key->ipv4_ttl, mask->ipv4_ttl);
flow_key->ip.ttl = nh->ttl;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jesse Gross | 134 | 50.19% | 1 | 20.00% |
Jarno Rajahalme | 85 | 31.84% | 1 | 20.00% |
Pravin B Shelar | 45 | 16.85% | 1 | 20.00% |
Joe Stringer | 2 | 0.75% | 1 | 20.00% |
Jiri Pirko | 1 | 0.37% | 1 | 20.00% |
Total | 267 | 100.00% | 5 | 100.00% |
static bool is_ipv6_mask_nonzero(const __be32 addr[4])
{
return !!(addr[0] | addr[1] | addr[2] | addr[3]);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jarno Rajahalme | 38 | 100.00% | 1 | 100.00% |
Total | 38 | 100.00% | 1 | 100.00% |
static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
const struct ovs_key_ipv6 *key,
const struct ovs_key_ipv6 *mask)
{
struct ipv6hdr *nh;
int err;
err = skb_ensure_writable(skb, skb_network_offset(skb) +
sizeof(struct ipv6hdr));
if (unlikely(err))
return err;
nh = ipv6_hdr(skb);
/* Setting an IP addresses is typically only a side effect of
* matching on them in the current userspace implementation, so it
* makes sense to check if the value actually changed.
*/
if (is_ipv6_mask_nonzero(mask->ipv6_src)) {
__be32 *saddr = (__be32 *)&nh->saddr;
__be32 masked[4];
mask_ipv6_addr(saddr, key->ipv6_src, mask->ipv6_src, masked);
if (unlikely(memcmp(saddr, masked, sizeof(masked)))) {
set_ipv6_addr(skb, flow_key->ip.proto, saddr, masked,
true);
memcpy(&flow_key->ipv6.addr.src, masked,
sizeof(flow_key->ipv6.addr.src));
}
}
if (is_ipv6_mask_nonzero(mask->ipv6_dst)) {
unsigned int offset = 0;
int flags = IP6_FH_F_SKIP_RH;
bool recalc_csum = true;
__be32 *daddr = (__be32 *)&nh->daddr;
__be32 masked[4];
mask_ipv6_addr(daddr, key->ipv6_dst, mask->ipv6_dst, masked);
if (unlikely(memcmp(daddr, masked, sizeof(masked)))) {
if (ipv6_ext_hdr(nh->nexthdr))
recalc_csum = (ipv6_find_hdr(skb, &offset,
NEXTHDR_ROUTING,
NULL, &flags)
!= NEXTHDR_ROUTING);
set_ipv6_addr(skb, flow_key->ip.proto, daddr, masked,
recalc_csum);
memcpy(&flow_key->ipv6