0f09dfe06c434db2b3df2784bcb1e29e5c631e61
[librecmc/librecmc.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 24 Mar 2021 02:30:35 +0100
3 Subject: [PATCH] net: bridge: resolve forwarding path for VLAN tag
4  actions in bridge devices
5
6 Depending on the VLAN settings of the bridge and the port, the bridge can
7 either add or remove a tag. When vlan filtering is enabled, the fdb lookup
8 also needs to know the VLAN tag/proto for the destination address
9 To provide this, keep track of the stack of VLAN tags for the path in the
10 lookup context
11
12 Signed-off-by: Felix Fietkau <nbd@nbd.name>
13 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
14 ---
15
16 --- a/include/linux/netdevice.h
17 +++ b/include/linux/netdevice.h
18 @@ -855,10 +855,20 @@ struct net_device_path {
19                         u16             id;
20                         __be16          proto;
21                 } encap;
22 +               struct {
23 +                       enum {
24 +                               DEV_PATH_BR_VLAN_KEEP,
25 +                               DEV_PATH_BR_VLAN_TAG,
26 +                               DEV_PATH_BR_VLAN_UNTAG,
27 +                       }               vlan_mode;
28 +                       u16             vlan_id;
29 +                       __be16          vlan_proto;
30 +               } bridge;
31         };
32  };
33  
34  #define NET_DEVICE_PATH_STACK_MAX      5
35 +#define NET_DEVICE_PATH_VLAN_MAX       2
36  
37  struct net_device_path_stack {
38         int                     num_paths;
39 @@ -868,6 +878,12 @@ struct net_device_path_stack {
40  struct net_device_path_ctx {
41         const struct net_device *dev;
42         const u8                *daddr;
43 +
44 +       int                     num_vlans;
45 +       struct {
46 +               u16             id;
47 +               __be16          proto;
48 +       } vlan[NET_DEVICE_PATH_VLAN_MAX];
49  };
50  
51  enum tc_setup_type {
52 --- a/net/8021q/vlan_dev.c
53 +++ b/net/8021q/vlan_dev.c
54 @@ -780,6 +780,12 @@ static int vlan_dev_fill_forward_path(st
55         path->encap.proto = vlan->vlan_proto;
56         path->dev = ctx->dev;
57         ctx->dev = vlan->real_dev;
58 +       if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
59 +               return -ENOSPC;
60 +
61 +       ctx->vlan[ctx->num_vlans].id = vlan->vlan_id;
62 +       ctx->vlan[ctx->num_vlans].proto = vlan->vlan_proto;
63 +       ctx->num_vlans++;
64  
65         return 0;
66  }
67 --- a/net/bridge/br_device.c
68 +++ b/net/bridge/br_device.c
69 @@ -409,7 +409,10 @@ static int br_fill_forward_path(struct n
70                 return -1;
71  
72         br = netdev_priv(ctx->dev);
73 -       f = br_fdb_find_rcu(br, ctx->daddr, 0);
74 +
75 +       br_vlan_fill_forward_path_pvid(br, ctx, path);
76 +
77 +       f = br_fdb_find_rcu(br, ctx->daddr, path->bridge.vlan_id);
78         if (!f || !f->dst)
79                 return -1;
80  
81 @@ -417,10 +420,28 @@ static int br_fill_forward_path(struct n
82         if (!dst)
83                 return -1;
84  
85 +       if (br_vlan_fill_forward_path_mode(br, dst, path))
86 +               return -1;
87 +
88         path->type = DEV_PATH_BRIDGE;
89         path->dev = dst->br->dev;
90         ctx->dev = dst->dev;
91  
92 +       switch (path->bridge.vlan_mode) {
93 +       case DEV_PATH_BR_VLAN_TAG:
94 +               if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
95 +                       return -ENOSPC;
96 +               ctx->vlan[ctx->num_vlans].id = path->bridge.vlan_id;
97 +               ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
98 +               ctx->num_vlans++;
99 +               break;
100 +       case DEV_PATH_BR_VLAN_UNTAG:
101 +               ctx->num_vlans--;
102 +               break;
103 +       case DEV_PATH_BR_VLAN_KEEP:
104 +               break;
105 +       }
106 +
107         return 0;
108  }
109  
110 --- a/net/bridge/br_private.h
111 +++ b/net/bridge/br_private.h
112 @@ -1093,6 +1093,13 @@ void br_vlan_notify(const struct net_bri
113  bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
114                              const struct net_bridge_vlan *range_end);
115  
116 +void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
117 +                                   struct net_device_path_ctx *ctx,
118 +                                   struct net_device_path *path);
119 +int br_vlan_fill_forward_path_mode(struct net_bridge *br,
120 +                                  struct net_bridge_port *dst,
121 +                                  struct net_device_path *path);
122 +
123  static inline struct net_bridge_vlan_group *br_vlan_group(
124                                         const struct net_bridge *br)
125  {
126 @@ -1250,6 +1257,19 @@ static inline int nbp_get_num_vlan_infos
127  {
128         return 0;
129  }
130 +
131 +static inline void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
132 +                                                 struct net_device_path_ctx *ctx,
133 +                                                 struct net_device_path *path)
134 +{
135 +}
136 +
137 +static inline int br_vlan_fill_forward_path_mode(struct net_bridge *br,
138 +                                                struct net_bridge_port *dst,
139 +                                                struct net_device_path *path)
140 +{
141 +       return 0;
142 +}
143  
144  static inline struct net_bridge_vlan_group *br_vlan_group(
145                                         const struct net_bridge *br)
146 --- a/net/bridge/br_vlan.c
147 +++ b/net/bridge/br_vlan.c
148 @@ -1327,6 +1327,59 @@ int br_vlan_get_pvid_rcu(const struct ne
149  }
150  EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
151  
152 +void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
153 +                                   struct net_device_path_ctx *ctx,
154 +                                   struct net_device_path *path)
155 +{
156 +       struct net_bridge_vlan_group *vg;
157 +       int idx = ctx->num_vlans - 1;
158 +       u16 vid;
159 +
160 +       path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
161 +
162 +       if (!br_opt_get(br, BROPT_VLAN_ENABLED))
163 +               return;
164 +
165 +       vg = br_vlan_group(br);
166 +
167 +       if (idx >= 0 &&
168 +           ctx->vlan[idx].proto == br->vlan_proto) {
169 +               vid = ctx->vlan[idx].id;
170 +       } else {
171 +               path->bridge.vlan_mode = DEV_PATH_BR_VLAN_TAG;
172 +               vid = br_get_pvid(vg);
173 +       }
174 +
175 +       path->bridge.vlan_id = vid;
176 +       path->bridge.vlan_proto = br->vlan_proto;
177 +}
178 +
179 +int br_vlan_fill_forward_path_mode(struct net_bridge *br,
180 +                                  struct net_bridge_port *dst,
181 +                                  struct net_device_path *path)
182 +{
183 +       struct net_bridge_vlan_group *vg;
184 +       struct net_bridge_vlan *v;
185 +
186 +       if (!br_opt_get(br, BROPT_VLAN_ENABLED))
187 +               return 0;
188 +
189 +       vg = nbp_vlan_group_rcu(dst);
190 +       v = br_vlan_find(vg, path->bridge.vlan_id);
191 +       if (!v || !br_vlan_should_use(v))
192 +               return -EINVAL;
193 +
194 +       if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
195 +               return 0;
196 +
197 +       if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
198 +               path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
199 +       else
200 +               path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
201 +
202 +       return 0;
203 +}
204 +
205  int br_vlan_get_info(const struct net_device *dev, u16 vid,
206                      struct bridge_vlan_info *p_vinfo)
207  {