aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Wang <alexw@nicira.com>2014-07-17 18:14:13 -0400
committerPravin B Shelar <pshelar@nicira.com>2014-07-24 04:15:04 -0400
commit5cd667b0a4567048bb555927d6ee564f4e5620a9 (patch)
tree34fc874b8e4e7ad420c25712bcc62039ede0337a
parentf6e675324481c56b358091ddb446b2c95a8e047b (diff)
openvswitch: Allow each vport to have an array of 'port_id's.
In order to allow handlers directly read upcalls from datapath, we need to support per-handler netlink socket for each vport in datapath. This commit makes this happen. Also, it is guaranteed to be backward compatible with previous branch. Signed-off-by: Alex Wang <alexw@nicira.com> Acked-by: Thomas Graf <tgraf@redhat.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
-rw-r--r--include/uapi/linux/openvswitch.h13
-rw-r--r--net/openvswitch/datapath.c23
-rw-r--r--net/openvswitch/vport.c101
-rw-r--r--net/openvswitch/vport.h27
4 files changed, 148 insertions, 16 deletions
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 0b979ee4bfc0..a794d1dd7b40 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -118,6 +118,9 @@ struct ovs_vport_stats {
118/* Allow last Netlink attribute to be unaligned */ 118/* Allow last Netlink attribute to be unaligned */
119#define OVS_DP_F_UNALIGNED (1 << 0) 119#define OVS_DP_F_UNALIGNED (1 << 0)
120 120
121/* Allow datapath to associate multiple Netlink PIDs to each vport */
122#define OVS_DP_F_VPORT_PIDS (1 << 1)
123
121/* Fixed logical ports. */ 124/* Fixed logical ports. */
122#define OVSP_LOCAL ((__u32)0) 125#define OVSP_LOCAL ((__u32)0)
123 126
@@ -203,9 +206,10 @@ enum ovs_vport_type {
203 * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes 206 * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes
204 * plus a null terminator. 207 * plus a null terminator.
205 * @OVS_VPORT_ATTR_OPTIONS: Vport-specific configuration information. 208 * @OVS_VPORT_ATTR_OPTIONS: Vport-specific configuration information.
206 * @OVS_VPORT_ATTR_UPCALL_PID: The Netlink socket in userspace that 209 * @OVS_VPORT_ATTR_UPCALL_PID: The array of Netlink socket pids in userspace
207 * OVS_PACKET_CMD_MISS upcalls will be directed to for packets received on 210 * among which OVS_PACKET_CMD_MISS upcalls will be distributed for packets
208 * this port. A value of zero indicates that upcalls should not be sent. 211 * received on this port. If this is a single-element array of value 0,
212 * upcalls should not be sent.
209 * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for 213 * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for
210 * packets sent or received through the vport. 214 * packets sent or received through the vport.
211 * 215 *
@@ -228,7 +232,8 @@ enum ovs_vport_attr {
228 OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */ 232 OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */
229 OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */ 233 OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */
230 OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */ 234 OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */
231 OVS_VPORT_ATTR_UPCALL_PID, /* u32 Netlink PID to receive upcalls */ 235 OVS_VPORT_ATTR_UPCALL_PID, /* array of u32 Netlink socket PIDs for */
236 /* receiving upcalls */
232 OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */ 237 OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */
233 __OVS_VPORT_ATTR_MAX 238 __OVS_VPORT_ATTR_MAX
234}; 239};
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 20f59b62721a..65a8e5c089e4 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -266,7 +266,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
266 upcall.cmd = OVS_PACKET_CMD_MISS; 266 upcall.cmd = OVS_PACKET_CMD_MISS;
267 upcall.key = &key; 267 upcall.key = &key;
268 upcall.userdata = NULL; 268 upcall.userdata = NULL;
269 upcall.portid = p->upcall_portid; 269 upcall.portid = ovs_vport_find_upcall_portid(p, skb);
270 ovs_dp_upcall(dp, skb, &upcall); 270 ovs_dp_upcall(dp, skb, &upcall);
271 consume_skb(skb); 271 consume_skb(skb);
272 stats_counter = &stats->n_missed; 272 stats_counter = &stats->n_missed;
@@ -1373,7 +1373,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
1373 parms.options = NULL; 1373 parms.options = NULL;
1374 parms.dp = dp; 1374 parms.dp = dp;
1375 parms.port_no = OVSP_LOCAL; 1375 parms.port_no = OVSP_LOCAL;
1376 parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); 1376 parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
1377 1377
1378 ovs_dp_change(dp, a); 1378 ovs_dp_change(dp, a);
1379 1379
@@ -1632,8 +1632,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
1632 1632
1633 if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || 1633 if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
1634 nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || 1634 nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
1635 nla_put_string(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport)) || 1635 nla_put_string(skb, OVS_VPORT_ATTR_NAME,
1636 nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_portid)) 1636 vport->ops->get_name(vport)))
1637 goto nla_put_failure; 1637 goto nla_put_failure;
1638 1638
1639 ovs_vport_get_stats(vport, &vport_stats); 1639 ovs_vport_get_stats(vport, &vport_stats);
@@ -1641,6 +1641,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
1641 &vport_stats)) 1641 &vport_stats))
1642 goto nla_put_failure; 1642 goto nla_put_failure;
1643 1643
1644 if (ovs_vport_get_upcall_portids(vport, skb))
1645 goto nla_put_failure;
1646
1644 err = ovs_vport_get_options(vport, skb); 1647 err = ovs_vport_get_options(vport, skb);
1645 if (err == -EMSGSIZE) 1648 if (err == -EMSGSIZE)
1646 goto error; 1649 goto error;
@@ -1762,7 +1765,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
1762 parms.options = a[OVS_VPORT_ATTR_OPTIONS]; 1765 parms.options = a[OVS_VPORT_ATTR_OPTIONS];
1763 parms.dp = dp; 1766 parms.dp = dp;
1764 parms.port_no = port_no; 1767 parms.port_no = port_no;
1765 parms.upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); 1768 parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
1766 1769
1767 vport = new_vport(&parms); 1770 vport = new_vport(&parms);
1768 err = PTR_ERR(vport); 1771 err = PTR_ERR(vport);
@@ -1812,8 +1815,14 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
1812 goto exit_unlock_free; 1815 goto exit_unlock_free;
1813 } 1816 }
1814 1817
1815 if (a[OVS_VPORT_ATTR_UPCALL_PID]) 1818
1816 vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); 1819 if (a[OVS_VPORT_ATTR_UPCALL_PID]) {
1820 struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID];
1821
1822 err = ovs_vport_set_upcall_portids(vport, ids);
1823 if (err)
1824 goto exit_unlock_free;
1825 }
1817 1826
1818 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, 1827 err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
1819 info->snd_seq, 0, OVS_VPORT_CMD_NEW); 1828 info->snd_seq, 0, OVS_VPORT_CMD_NEW);
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 42c0f4a0b78c..702fb21bfe15 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -134,10 +134,12 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
134 134
135 vport->dp = parms->dp; 135 vport->dp = parms->dp;
136 vport->port_no = parms->port_no; 136 vport->port_no = parms->port_no;
137 vport->upcall_portid = parms->upcall_portid;
138 vport->ops = ops; 137 vport->ops = ops;
139 INIT_HLIST_NODE(&vport->dp_hash_node); 138 INIT_HLIST_NODE(&vport->dp_hash_node);
140 139
140 if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids))
141 return ERR_PTR(-EINVAL);
142
141 vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 143 vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
142 if (!vport->percpu_stats) { 144 if (!vport->percpu_stats) {
143 kfree(vport); 145 kfree(vport);
@@ -161,6 +163,10 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
161 */ 163 */
162void ovs_vport_free(struct vport *vport) 164void ovs_vport_free(struct vport *vport)
163{ 165{
166 /* vport is freed from RCU callback or error path, Therefore
167 * it is safe to use raw dereference.
168 */
169 kfree(rcu_dereference_raw(vport->upcall_portids));
164 free_percpu(vport->percpu_stats); 170 free_percpu(vport->percpu_stats);
165 kfree(vport); 171 kfree(vport);
166} 172}
@@ -327,6 +333,99 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb)
327} 333}
328 334
329/** 335/**
336 * ovs_vport_set_upcall_portids - set upcall portids of @vport.
337 *
338 * @vport: vport to modify.
339 * @ids: new configuration, an array of port ids.
340 *
341 * Sets the vport's upcall_portids to @ids.
342 *
343 * Returns 0 if successful, -EINVAL if @ids is zero length or cannot be parsed
344 * as an array of U32.
345 *
346 * Must be called with ovs_mutex.
347 */
348int ovs_vport_set_upcall_portids(struct vport *vport, struct nlattr *ids)
349{
350 struct vport_portids *old, *vport_portids;
351
352 if (!nla_len(ids) || nla_len(ids) % sizeof(u32))
353 return -EINVAL;
354
355 old = ovsl_dereference(vport->upcall_portids);
356
357 vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids),