-/* Modifies 'target' to store the rcu_dereferenced pointer that was used to do
- * the comparision. */
-static int port_cmp(const struct tbl_node *node, void *target)
-{
- const struct gre_vport *gre_vport = gre_vport_table_cast(node);
- struct port_lookup_key *lookup = target;
-
- lookup->mutable = rcu_dereference(gre_vport->mutable);
-
- return ((lookup->mutable->port_config.flags & GRE_F_IN_KEY_MATCH) ==
- lookup->vals[LOOKUP_KEY_MATCH]) &&
- lookup->mutable->port_config.daddr == lookup->vals[LOOKUP_DADDR] &&
- lookup->mutable->port_config.in_key == lookup->vals[LOOKUP_KEY] &&
- lookup->mutable->port_config.saddr == lookup->vals[LOOKUP_SADDR];
-}
-
-static u32 port_hash(struct port_lookup_key *lookup)
-{
- return jhash2(lookup->vals, ARRAY_SIZE(lookup->vals), 0);
-}
-
-static int add_port(struct vport *vport)
-{
- struct gre_vport *gre_vport = gre_vport_priv(vport);
- struct port_lookup_key lookup;
- int err;
-
- if (!port_table) {
- struct tbl *new_table;
-
- new_table = tbl_create(0);
- if (!new_table)
- return -ENOMEM;
-
- rcu_assign_pointer(port_table, new_table);
-
- } else if (tbl_count(port_table) > tbl_n_buckets(port_table)) {
- struct tbl *old_table = port_table;
- struct tbl *new_table;
-
- new_table = tbl_expand(old_table);
- if (IS_ERR(new_table))
- return PTR_ERR(new_table);
-
- rcu_assign_pointer(port_table, new_table);
- tbl_deferred_destroy(old_table, NULL);
- }
-
- lookup.vals[LOOKUP_SADDR] = gre_vport->mutable->port_config.saddr;
- lookup.vals[LOOKUP_DADDR] = gre_vport->mutable->port_config.daddr;
- lookup.vals[LOOKUP_KEY] = gre_vport->mutable->port_config.in_key;
- lookup.vals[LOOKUP_KEY_MATCH] = gre_vport->mutable->port_config.flags & GRE_F_IN_KEY_MATCH;
-
- err = tbl_insert(port_table, &gre_vport->tbl_node, port_hash(&lookup));
- if (err)
- return err;
-
- (*find_port_pool(gre_vport->mutable))++;
-
- return 0;
-}
-
-static int del_port(struct vport *vport)
-{
- struct gre_vport *gre_vport = gre_vport_priv(vport);
- int err;
-
- err = tbl_remove(port_table, &gre_vport->tbl_node);
- if (err)
- return err;
-
- (*find_port_pool(gre_vport->mutable))--;
-
- return 0;
-}
-
-#define FIND_PORT_KEY (1 << 0)
-#define FIND_PORT_MATCH (1 << 1)
-#define FIND_PORT_ANY (FIND_PORT_KEY | FIND_PORT_MATCH)
-
-static struct vport *find_port(__be32 saddr, __be32 daddr, __be32 key,
- int port_type,
- const struct mutable_config **mutable)
-{
- struct port_lookup_key lookup;
- struct tbl *table = rcu_dereference(port_table);
- struct tbl_node *tbl_node;
-
- if (!table)
- return NULL;
-
- lookup.vals[LOOKUP_SADDR] = saddr;
- lookup.vals[LOOKUP_DADDR] = daddr;
-
- if (port_type & FIND_PORT_KEY) {
- lookup.vals[LOOKUP_KEY] = key;
- lookup.vals[LOOKUP_KEY_MATCH] = 0;
-
- if (key_local_remote_ports) {
- tbl_node = tbl_lookup(table, &lookup, port_hash(&lookup), port_cmp);
- if (tbl_node)
- goto found;
- }
-
- if (key_remote_ports) {
- lookup.vals[LOOKUP_SADDR] = 0;
-
- tbl_node = tbl_lookup(table, &lookup, port_hash(&lookup), port_cmp);
- if (tbl_node)
- goto found;
-
- lookup.vals[LOOKUP_SADDR] = saddr;
- }
- }
-
- if (port_type & FIND_PORT_MATCH) {
- lookup.vals[LOOKUP_KEY] = 0;
- lookup.vals[LOOKUP_KEY_MATCH] = GRE_F_IN_KEY_MATCH;
-
- if (local_remote_ports) {
- tbl_node = tbl_lookup(table, &lookup, port_hash(&lookup), port_cmp);
- if (tbl_node)
- goto found;
- }
-
- if (remote_ports) {
- lookup.vals[LOOKUP_SADDR] = 0;
-
- tbl_node = tbl_lookup(table, &lookup, port_hash(&lookup), port_cmp);
- if (tbl_node)
- goto found;
- }
- }
-
- return NULL;
-
-found:
- *mutable = lookup.mutable;
- return gre_vport_to_vport(gre_vport_table_cast(tbl_node));
-}
-
-static bool check_ipv4_address(__be32 addr)