aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Durrant <Paul.Durrant@citrix.com>2015-09-02 12:58:36 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-02 14:45:00 -0400
commit210c34dcd8d912dcc740f1f17625a7293af5cb56 (patch)
tree33b7944163879cad30a6e631490ad6d2d3297164
parent4db78d31deff77f227de56316ee865d65eaa7f01 (diff)
xen-netback: add support for multicast control
Xen's PV network protocol includes messages to add/remove ethernet multicast addresses to/from a filter list in the backend. This allows the frontend to request the backend only forward multicast packets which are of interest thus preventing unnecessary noise on the shared ring. The canonical netif header in git://xenbits.xen.org/xen.git specifies the message format (two more XEN_NETIF_EXTRA_TYPEs) so the minimal necessary changes have been pulled into include/xen/interface/io/netif.h. To prevent the frontend from extending the multicast filter list arbitrarily a limit (XEN_NETBK_MCAST_MAX) has been set to 64 entries. This limit is not specified by the protocol and so may change in future. If the limit is reached then the next XEN_NETIF_EXTRA_TYPE_MCAST_ADD sent by the frontend will be failed with NETIF_RSP_ERROR. Signed-off-by: Paul Durrant <paul.durrant@citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: Wei Liu <wei.liu2@citrix.com> Acked-by: Wei Liu <wei.liu2@citrix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/xen-netback/common.h15
-rw-r--r--drivers/net/xen-netback/interface.c10
-rw-r--r--drivers/net/xen-netback/netback.c99
-rw-r--r--drivers/net/xen-netback/xenbus.c13
-rw-r--r--include/xen/interface/io/netif.h8
5 files changed, 144 insertions, 1 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index c6cb85a85c89..6dc76c1e807b 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -210,12 +210,22 @@ enum state_bit_shift {
210 VIF_STATUS_CONNECTED, 210 VIF_STATUS_CONNECTED,
211}; 211};
212 212
213struct xenvif_mcast_addr {
214 struct list_head entry;
215 struct rcu_head rcu;
216 u8 addr[6];
217};
218
219#define XEN_NETBK_MCAST_MAX 64
220
213struct xenvif { 221struct xenvif {
214 /* Unique identifier for this interface. */ 222 /* Unique identifier for this interface. */
215 domid_t domid; 223 domid_t domid;
216 unsigned int handle; 224 unsigned int handle;
217 225
218 u8 fe_dev_addr[6]; 226 u8 fe_dev_addr[6];
227 struct list_head fe_mcast_addr;
228 unsigned int fe_mcast_count;
219 229
220 /* Frontend feature information. */ 230 /* Frontend feature information. */
221 int gso_mask; 231 int gso_mask;
@@ -224,6 +234,7 @@ struct xenvif {
224 u8 can_sg:1; 234 u8 can_sg:1;
225 u8 ip_csum:1; 235 u8 ip_csum:1;
226 u8 ipv6_csum:1; 236 u8 ipv6_csum:1;
237 u8 multicast_control:1;
227 238
228 /* Is this interface disabled? True when backend discovers 239 /* Is this interface disabled? True when backend discovers
229 * frontend is rogue. 240 * frontend is rogue.
@@ -341,4 +352,8 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue,
341 struct sk_buff *skb); 352 struct sk_buff *skb);
342void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue); 353void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue);
343 354
355/* Multicast control */
356bool xenvif_mcast_match(struct xenvif *vif, const u8 *addr);
357void xenvif_mcast_addr_list_free(struct xenvif *vif);
358
344#endif /* __XEN_NETBACK__COMMON_H__ */ 359#endif /* __XEN_NETBACK__COMMON_H__ */
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 28577a31549d..e7bd63eb2876 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -171,6 +171,13 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
171 !xenvif_schedulable(vif)) 171 !xenvif_schedulable(vif))
172 goto drop; 172 goto drop;
173 173
174 if (vif->multicast_control && skb->pkt_type == PACKET_MULTICAST) {
175 struct ethhdr *eth = (struct ethhdr *)skb->data;
176
177 if (!xenvif_mcast_match(vif, eth->h_dest))
178 goto drop;
179 }
180
174 cb = XENVIF_RX_CB(skb); 181 cb = XENVIF_RX_CB(skb);
175 cb->expires = jiffies + vif->drain_timeout; 182 cb->expires = jiffies + vif->drain_timeout;
176 183
@@ -427,6 +434,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
427 vif->num_queues = 0; 434 vif->num_queues = 0;
428 435
429 spin_lock_init(&vif->lock); 436 spin_lock_init(&vif->lock);
437 INIT_LIST_HEAD(&vif->fe_mcast_addr);
430 438
431 dev->netdev_ops = &xenvif_netdev_ops; 439 dev->netdev_ops = &xenvif_netdev_ops;
432 dev->hw_features = NETIF_F_SG | 440 dev->hw_features = NETIF_F_SG |
@@ -661,6 +669,8 @@ void xenvif_disconnect(struct xenvif *vif)
661 669
662 xenvif_unmap_frontend_rings(queue); 670 xenvif_unmap_frontend_rings(queue);
663 } 671 }
672
673 xenvif_mcast_addr_list_free(vif);
664} 674}
665 675
666/* Reverse the relevant parts of xenvif_init_queue(). 676/* Reverse the relevant parts of xenvif_init_queue().
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 3f44b522b831..42569b994ea8 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1157,6 +1157,80 @@ static bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size)
1157 return false; 1157 return false;
1158} 1158}
1159 1159
1160/* No locking is required in xenvif_mcast_add/del() as they are
1161 * only ever invoked from NAPI poll. An RCU list is used because
1162 * xenvif_mcast_match() is called asynchronously, during start_xmit.
1163 */
1164
1165static int xenvif_mcast_add(struct xenvif *vif, const u8 *addr)
1166{
1167 struct xenvif_mcast_addr *mcast;
1168
1169 if (vif->fe_mcast_count == XEN_NETBK_MCAST_MAX) {
1170 if (net_ratelimit())
1171 netdev_err(vif->dev,
1172 "Too many multicast addresses\n");
1173 return -ENOSPC;
1174 }
1175
1176 mcast = kzalloc(sizeof(*mcast), GFP_ATOMIC);
1177 if (!mcast)
1178 return -ENOMEM;
1179
1180 ether_addr_copy(mcast->addr, addr);
1181 list_add_tail_rcu(&mcast->entry, &vif->fe_mcast_addr);
1182 vif->fe_mcast_count++;
1183
1184 return 0;
1185}
1186
1187static void xenvif_mcast_del(struct xenvif *vif, const u8 *addr)
1188{
1189 struct xenvif_mcast_addr *mcast;
1190
1191 list_for_each_entry_rcu(mcast, &vif->fe_mcast_addr, entry) {
1192 if (ether_addr_equal(addr, mcast->addr)) {
1193 --vif->fe_mcast_count;
1194 list_del_rcu(&mcast->entry);
1195 kfree_rcu(mcast, rcu);
1196 break;
1197 }
1198 }
1199}
1200
1201bool xenvif_mcast_match(struct xenvif *vif, const u8 *addr)
1202{
1203 struct xenvif_mcast_addr *mcast;
1204
1205 rcu_read_lock();
1206 list_for_each_entry_rcu(mcast, &vif->fe_mcast_addr, entry) {
1207 if (ether_addr_equal(addr, mcast->addr)) {
1208 rcu_read_unlock();
1209 return true;
1210 }
1211 }
1212 rcu_read_unlock();
1213
1214 return false;
1215}
1216
1217void xenvif_mcast_addr_list_free(struct xenvif *vif)
1218{
1219 /* No need for locking or RCU here. NAPI poll and TX queue
1220 * are stopped.
1221 */
1222 while (!list_empty(&vif->fe_mcast_addr)) {
1223 struct xenvif_mcast_addr *mcast;
1224
1225 mcast = list_first_entry(&vif->fe_mcast_addr,
1226 struct xenvif_mcast_addr,
1227 entry);
1228 --vif->fe_mcast_count;
1229 list_del(&mcast->entry);
1230 kfree(mcast);
1231 }
1232}
1233
1160static void xenvif_tx_build_gops(struct xenvif_queue *queue, 1234static void xenvif_tx_build_gops(struct xenvif_queue *queue,
1161 int budget, 1235 int budget,
1162 unsigned *copy_ops, 1236 unsigned *copy_ops,
@@ -1215,6 +1289,31 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
1215 break; 1289 break;
1216 } 1290 }
1217 1291
1292 if (extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1].type) {
1293 struct xen_netif_extra_info *extra;
1294
1295 extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1];
1296 ret = xenvif_mcast_add(queue->vif, extra->u.mcast.addr);
1297
1298 make_tx_response(queue, &txreq,
1299 (ret == 0) ?
1300 XEN_NETIF_RSP_OKAY :
1301 XEN_NETIF_RSP_ERROR);
1302 push_tx_responses(queue);
1303 continue;
1304 }
1305
1306 if (extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1].type) {
1307 struct xen_netif_extra_info *extra;
1308
1309 extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1];
1310 xenvif_mcast_del(queue->vif, extra->u.mcast.addr);
1311
1312 make_tx_response(queue, &txreq, XEN_NETIF_RSP_OKAY);
1313 push_tx_responses(queue);
1314 continue;
1315 }
1316
1218 ret = xenvif_count_requests(queue, &txreq, txfrags, work_to_do); 1317 ret = xenvif_count_requests(queue, &txreq, txfrags, work_to_do);
1219 if (unlikely(ret < 0)) 1318 if (unlikely(ret < 0))
1220 break; 1319 break;
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index ec383b0f5443..929a6e7e5ecf 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -327,6 +327,14 @@ static int netback_probe(struct xenbus_device *dev,
327 goto abort_transaction; 327 goto abort_transaction;
328 } 328 }
329 329
330 /* We support multicast-control. */
331 err = xenbus_printf(xbt, dev->nodename,
332 "feature-multicast-control", "%d", 1);
333 if (err) {
334 message = "writing feature-multicast-control";
335 goto abort_transaction;
336 }
337
330 err = xenbus_transaction_end(xbt, 0); 338 err = xenbus_transaction_end(xbt, 0);
331 } while (err == -EAGAIN); 339 } while (err == -EAGAIN);
332 340
@@ -1016,6 +1024,11 @@ static int read_xenbus_vif_flags(struct backend_info *be)
1016 val = 0; 1024 val = 0;
1017 vif->ipv6_csum = !!val; 1025 vif->ipv6_csum = !!val;
1018 1026
1027 if (xenbus_scanf(XBT_NIL, dev->otherend, "request-multicast-control",
1028 "%d", &val) < 0)
1029 val = 0;
1030 vif->multicast_control = !!val;
1031
1019 return 0; 1032 return 0;
1020} 1033}
1021 1034
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
index 70054cc0708d..252ffd4801ef 100644
--- a/include/xen/interface/io/netif.h
+++ b/include/xen/interface/io/netif.h
@@ -156,7 +156,9 @@ struct xen_netif_tx_request {
156/* Types of xen_netif_extra_info descriptors. */ 156/* Types of xen_netif_extra_info descriptors. */
157#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */ 157#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
158#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */ 158#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
159#define XEN_NETIF_EXTRA_TYPE_MAX (2) 159#define XEN_NETIF_EXTRA_TYPE_MCAST_ADD (2) /* u.mcast */
160#define XEN_NETIF_EXTRA_TYPE_MCAST_DEL (3) /* u.mcast */
161#define XEN_NETIF_EXTRA_TYPE_MAX (4)
160 162
161/* xen_netif_extra_info flags. */ 163/* xen_netif_extra_info flags. */
162#define _XEN_NETIF_EXTRA_FLAG_MORE (0) 164#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
@@ -201,6 +203,10 @@ struct xen_netif_extra_info {
201 uint16_t features; /* XEN_NETIF_GSO_FEAT_* */ 203 uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
202 } gso; 204 } gso;
203 205
206 struct {
207 uint8_t addr[6]; /* Address to add/remove. */
208 } mcast;
209
204 uint16_t pad[3]; 210 uint16_t pad[3];
205 } u; 211 } u;
206}; 212};