return reply.type == ODP_VPORT_TYPE_INTERNAL;
}
+int
+dpif_linux_vport_send(int dp_ifindex, uint32_t port_no,
+ const void *data, size_t size)
+{
+ struct odp_header *execute;
+ struct ofpbuf *buf;
+ size_t actions_ofs;
+ int error;
+
+ buf = ofpbuf_new(128 + size);
+
+ nl_msg_put_genlmsghdr(buf, 0, odp_packet_family, NLM_F_REQUEST,
+ ODP_PACKET_CMD_EXECUTE, 1);
+
+ execute = ofpbuf_put_uninit(buf, sizeof *execute);
+ execute->dp_ifindex = dp_ifindex;
+
+ nl_msg_put_unspec(buf, ODP_PACKET_ATTR_PACKET, data, size);
+
+ actions_ofs = nl_msg_start_nested(buf, ODP_PACKET_ATTR_ACTIONS);
+ nl_msg_put_u32(buf, ODP_ACTION_ATTR_OUTPUT, port_no);
+ nl_msg_end_nested(buf, actions_ofs);
+
+ error = nl_sock_transact(genl_sock, buf, NULL);
+ ofpbuf_delete(buf);
+ return error;
+}
+
static void
dpif_linux_port_changed(const struct rtnetlink_link_change *change,
void *dpif_)
struct netdev_dev_vport {
struct netdev_dev netdev_dev;
struct ofpbuf *options;
+ int dp_ifindex; /* -1 if unknown. */
+ uint32_t port_no; /* UINT32_MAX if unknown. */
};
struct netdev_vport {
const struct vport_class *vport_class = vport_class_cast(netdev_class);
struct ofpbuf *options = NULL;
struct shash fetched_args;
+ int dp_ifindex;
+ uint32_t port_no;
int error;
shash_init(&fetched_args);
+ dp_ifindex = -1;
+ port_no = UINT32_MAX;
if (!shash_is_empty(args)) {
/* Parse the provided configuration. */
options = ofpbuf_new(64);
name, strerror(error));
} else {
options = ofpbuf_clone_data(reply.options, reply.options_len);
+ dp_ifindex = reply.dp_ifindex;
+ port_no = reply.port_no;
}
ofpbuf_delete(buf);
} else {
shash_is_empty(&fetched_args) ? args : &fetched_args,
netdev_class);
dev->options = options;
+ dev->dp_ifindex = dp_ifindex;
+ dev->port_no = port_no;
*netdev_devp = &dev->netdev_dev;
route_table_register();
return error;
}
+static int
+netdev_vport_send(struct netdev *netdev, const void *data, size_t size)
+{
+ struct netdev_dev *dev_ = netdev_get_dev(netdev);
+ struct netdev_dev_vport *dev = netdev_dev_vport_cast(dev_);
+
+ if (dev->dp_ifindex == -1) {
+ const char *name = netdev_get_name(netdev);
+ struct dpif_linux_vport reply;
+ struct ofpbuf *buf;
+ int error;
+
+ error = dpif_linux_vport_get(name, &reply, &buf);
+ if (error) {
+ VLOG_ERR_RL(&rl, "%s: failed to query vport for send (%s)",
+ name, strerror(error));
+ return error;
+ }
+ dev->dp_ifindex = reply.dp_ifindex;
+ dev->port_no = reply.port_no;
+ ofpbuf_delete(buf);
+ }
+
+ return dpif_linux_vport_send(dev->dp_ifindex, dev->port_no, data, size);
+}
+
static int
netdev_vport_set_etheraddr(struct netdev *netdev,
const uint8_t mac[ETH_ADDR_LEN])
NULL, /* recv_wait */ \
NULL, /* drain */ \
\
- NULL, /* send */ \
+ netdev_vport_send, /* send */ \
NULL, /* send_wait */ \
\
netdev_vport_set_etheraddr, \