Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Bridge per vlan tunnel port dst_metadata handling code
0004  *
0005  *  Authors:
0006  *  Roopa Prabhu        <roopa@cumulusnetworks.com>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/netdevice.h>
0011 #include <linux/rtnetlink.h>
0012 #include <linux/slab.h>
0013 #include <net/switchdev.h>
0014 #include <net/dst_metadata.h>
0015 
0016 #include "br_private.h"
0017 #include "br_private_tunnel.h"
0018 
0019 static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
0020                     const void *ptr)
0021 {
0022     const struct net_bridge_vlan *vle = ptr;
0023     __be64 tunid = *(__be64 *)arg->key;
0024 
0025     return vle->tinfo.tunnel_id != tunid;
0026 }
0027 
0028 static const struct rhashtable_params br_vlan_tunnel_rht_params = {
0029     .head_offset = offsetof(struct net_bridge_vlan, tnode),
0030     .key_offset = offsetof(struct net_bridge_vlan, tinfo.tunnel_id),
0031     .key_len = sizeof(__be64),
0032     .nelem_hint = 3,
0033     .obj_cmpfn = br_vlan_tunid_cmp,
0034     .automatic_shrinking = true,
0035 };
0036 
0037 static struct net_bridge_vlan *br_vlan_tunnel_lookup(struct rhashtable *tbl,
0038                              __be64 tunnel_id)
0039 {
0040     return rhashtable_lookup_fast(tbl, &tunnel_id,
0041                       br_vlan_tunnel_rht_params);
0042 }
0043 
0044 static void vlan_tunnel_info_release(struct net_bridge_vlan *vlan)
0045 {
0046     struct metadata_dst *tdst = rtnl_dereference(vlan->tinfo.tunnel_dst);
0047 
0048     WRITE_ONCE(vlan->tinfo.tunnel_id, 0);
0049     RCU_INIT_POINTER(vlan->tinfo.tunnel_dst, NULL);
0050     dst_release(&tdst->dst);
0051 }
0052 
0053 void vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
0054               struct net_bridge_vlan *vlan)
0055 {
0056     if (!rcu_access_pointer(vlan->tinfo.tunnel_dst))
0057         return;
0058     rhashtable_remove_fast(&vg->tunnel_hash, &vlan->tnode,
0059                    br_vlan_tunnel_rht_params);
0060     vlan_tunnel_info_release(vlan);
0061 }
0062 
0063 static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
0064                   struct net_bridge_vlan *vlan, u32 tun_id)
0065 {
0066     struct metadata_dst *metadata = rtnl_dereference(vlan->tinfo.tunnel_dst);
0067     __be64 key = key32_to_tunnel_id(cpu_to_be32(tun_id));
0068     int err;
0069 
0070     if (metadata)
0071         return -EEXIST;
0072 
0073     metadata = __ip_tun_set_dst(0, 0, 0, 0, 0, TUNNEL_KEY,
0074                     key, 0);
0075     if (!metadata)
0076         return -EINVAL;
0077 
0078     metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_BRIDGE;
0079     rcu_assign_pointer(vlan->tinfo.tunnel_dst, metadata);
0080     WRITE_ONCE(vlan->tinfo.tunnel_id, key);
0081 
0082     err = rhashtable_lookup_insert_fast(&vg->tunnel_hash, &vlan->tnode,
0083                         br_vlan_tunnel_rht_params);
0084     if (err)
0085         goto out;
0086 
0087     return 0;
0088 out:
0089     vlan_tunnel_info_release(vlan);
0090 
0091     return err;
0092 }
0093 
0094 /* Must be protected by RTNL.
0095  * Must be called with vid in range from 1 to 4094 inclusive.
0096  */
0097 int nbp_vlan_tunnel_info_add(const struct net_bridge_port *port, u16 vid,
0098                  u32 tun_id)
0099 {
0100     struct net_bridge_vlan_group *vg;
0101     struct net_bridge_vlan *vlan;
0102 
0103     ASSERT_RTNL();
0104 
0105     vg = nbp_vlan_group(port);
0106     vlan = br_vlan_find(vg, vid);
0107     if (!vlan)
0108         return -EINVAL;
0109 
0110     return __vlan_tunnel_info_add(vg, vlan, tun_id);
0111 }
0112 
0113 /* Must be protected by RTNL.
0114  * Must be called with vid in range from 1 to 4094 inclusive.
0115  */
0116 int nbp_vlan_tunnel_info_delete(const struct net_bridge_port *port, u16 vid)
0117 {
0118     struct net_bridge_vlan_group *vg;
0119     struct net_bridge_vlan *v;
0120 
0121     ASSERT_RTNL();
0122 
0123     vg = nbp_vlan_group(port);
0124     v = br_vlan_find(vg, vid);
0125     if (!v)
0126         return -ENOENT;
0127 
0128     vlan_tunnel_info_del(vg, v);
0129 
0130     return 0;
0131 }
0132 
0133 static void __vlan_tunnel_info_flush(struct net_bridge_vlan_group *vg)
0134 {
0135     struct net_bridge_vlan *vlan, *tmp;
0136 
0137     list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist)
0138         vlan_tunnel_info_del(vg, vlan);
0139 }
0140 
0141 void nbp_vlan_tunnel_info_flush(struct net_bridge_port *port)
0142 {
0143     struct net_bridge_vlan_group *vg;
0144 
0145     ASSERT_RTNL();
0146 
0147     vg = nbp_vlan_group(port);
0148     __vlan_tunnel_info_flush(vg);
0149 }
0150 
0151 int vlan_tunnel_init(struct net_bridge_vlan_group *vg)
0152 {
0153     return rhashtable_init(&vg->tunnel_hash, &br_vlan_tunnel_rht_params);
0154 }
0155 
0156 void vlan_tunnel_deinit(struct net_bridge_vlan_group *vg)
0157 {
0158     rhashtable_destroy(&vg->tunnel_hash);
0159 }
0160 
0161 void br_handle_ingress_vlan_tunnel(struct sk_buff *skb,
0162                    struct net_bridge_port *p,
0163                    struct net_bridge_vlan_group *vg)
0164 {
0165     struct ip_tunnel_info *tinfo = skb_tunnel_info(skb);
0166     struct net_bridge_vlan *vlan;
0167 
0168     if (!vg || !tinfo)
0169         return;
0170 
0171     /* if already tagged, ignore */
0172     if (skb_vlan_tagged(skb))
0173         return;
0174 
0175     /* lookup vid, given tunnel id */
0176     vlan = br_vlan_tunnel_lookup(&vg->tunnel_hash, tinfo->key.tun_id);
0177     if (!vlan)
0178         return;
0179 
0180     skb_dst_drop(skb);
0181 
0182     __vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
0183 }
0184 
0185 int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
0186                  struct net_bridge_vlan *vlan)
0187 {
0188     struct metadata_dst *tunnel_dst;
0189     __be64 tunnel_id;
0190     int err;
0191 
0192     if (!vlan)
0193         return 0;
0194 
0195     tunnel_id = READ_ONCE(vlan->tinfo.tunnel_id);
0196     if (!tunnel_id || unlikely(!skb_vlan_tag_present(skb)))
0197         return 0;
0198 
0199     skb_dst_drop(skb);
0200     err = skb_vlan_pop(skb);
0201     if (err)
0202         return err;
0203 
0204     tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
0205     if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
0206         skb_dst_set(skb, &tunnel_dst->dst);
0207 
0208     return 0;
0209 }