diff options
| author | Alex Wang <alexw@nicira.com> | 2014-07-17 18:14:13 -0400 |
|---|---|---|
| committer | Pravin B Shelar <pshelar@nicira.com> | 2014-07-24 04:15:04 -0400 |
| commit | 5cd667b0a4567048bb555927d6ee564f4e5620a9 (patch) | |
| tree | 34fc874b8e4e7ad420c25712bcc62039ede0337a | |
| parent | f6e675324481c56b358091ddb446b2c95a8e047b (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.h | 13 | ||||
| -rw-r--r-- | net/openvswitch/datapath.c | 23 | ||||
| -rw-r--r-- | net/openvswitch/vport.c | 101 | ||||
| -rw-r--r-- | net/openvswitch/vport.h | 27 |
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 | */ |
| 162 | void ovs_vport_free(struct vport *vport) | 164 | void 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 | */ | ||
| 348 | int 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), | ||
