indigo_error_t indigo_port_stats_get( of_port_stats_request_t *port_stats_request, of_port_stats_reply_t **port_stats_reply_ptr) { of_port_no_t req_of_port_num; of_port_stats_reply_t *port_stats_reply; indigo_error_t err = INDIGO_ERROR_NONE; port_stats_reply = of_port_stats_reply_new(port_stats_request->version); if (port_stats_reply == NULL) { err = INDIGO_ERROR_RESOURCE; goto out; } of_list_port_stats_entry_t list; of_port_stats_reply_entries_bind(port_stats_reply, &list); of_port_stats_request_port_no_get(port_stats_request, &req_of_port_num); int dump_all = req_of_port_num == OF_PORT_DEST_NONE_BY_VERSION(port_stats_request->version); /* Refresh statistics */ nl_cache_refill(route_cache_sock, link_cache); struct nl_msg *msg = ind_ovs_create_nlmsg(ovs_vport_family, OVS_VPORT_CMD_GET); if (dump_all) { nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP; } else { nla_put_u32(msg, OVS_VPORT_ATTR_PORT_NO, req_of_port_num); } /* Ask kernel to send us one or more OVS_VPORT_CMD_NEW messages */ if (nl_send_auto(ind_ovs_socket, msg) < 0) { err = INDIGO_ERROR_UNKNOWN; goto out; } ind_ovs_nlmsg_freelist_free(msg); /* Handle OVS_VPORT_CMD_NEW messages */ nl_cb_set(netlink_callbacks, NL_CB_VALID, NL_CB_CUSTOM, port_stats_iterator, &list); if (nl_recvmsgs(ind_ovs_socket, netlink_callbacks) < 0) { err = INDIGO_ERROR_UNKNOWN; goto out; } out: if (err != INDIGO_ERROR_NONE) { of_port_stats_reply_delete(port_stats_reply); port_stats_reply = NULL; } *port_stats_reply_ptr = port_stats_reply; return err; }
/* * ind_ovs_port_deleted will free the port struct. */ indigo_error_t indigo_port_interface_remove( indigo_port_name_t port_name) { struct ind_ovs_port *port = ind_ovs_port_lookup_by_name(port_name); if (port == NULL) { return INDIGO_ERROR_NOT_FOUND; } struct nl_msg *msg = ind_ovs_create_nlmsg(ovs_vport_family, OVS_VPORT_CMD_DEL); nla_put_u32(msg, OVS_VPORT_ATTR_PORT_NO, port->dp_port_no); return ind_ovs_transact(msg); }
/* * This function just asks the datapath to add the port. If that succeeds we'll * get a OVS_VPORT_CMD_NEW multicast message. At that point ind_ovs_port_added * will create our own representation of the port. This is to support using * ovs-dpctl to add and remove ports. */ indigo_error_t indigo_port_interface_add( indigo_port_name_t port_name, of_port_no_t of_port, indigo_port_config_t *config) { assert(of_port < IND_OVS_MAX_PORTS); assert(strlen(port_name) < 256); struct nl_msg *msg = ind_ovs_create_nlmsg(ovs_vport_family, OVS_VPORT_CMD_NEW); nla_put_u32(msg, OVS_VPORT_ATTR_TYPE, OVS_VPORT_TYPE_NETDEV); nla_put_string(msg, OVS_VPORT_ATTR_NAME, port_name); nla_put_u32(msg, OVS_VPORT_ATTR_PORT_NO, of_port); nla_put_u32(msg, OVS_VPORT_ATTR_UPCALL_PID, 0); return ind_ovs_transact(msg); }
/* * See the OF_PORT_DEST_USE_TABLE comment in ind_ovs_translate_actions. * This is mostly the same as ind_ovs_handle_packet_miss but does * not reuse the original message for the execute command since * the incoming message has a userdata attribute. * It also doesn't install a kflow or update flow stats. */ static void ind_ovs_handle_packet_table(struct ind_ovs_upcall_thread *thread, struct ind_ovs_port *port, struct nl_msg *msg, struct nlattr **attrs) { struct nlattr *key = attrs[OVS_PACKET_ATTR_KEY]; struct nlattr *packet = attrs[OVS_PACKET_ATTR_PACKET]; assert(key && packet); struct ind_ovs_parsed_key pkey; ind_ovs_parse_key(key, &pkey); /* Lookup the flow in the userspace flowtable. */ struct ind_ovs_flow *flow; if (ind_ovs_lookup_flow(&pkey, &flow) != 0) { ind_ovs_upcall_request_pktin(pkey.in_port, port, packet, key, OF_PACKET_IN_REASON_NO_MATCH); return; } /* Send OVS_PACKET_CMD_EXECUTE. */ /* TODO ensure the message is large enough */ struct nl_msg *reply = ind_ovs_create_nlmsg(ovs_packet_family, OVS_PACKET_CMD_EXECUTE); ind_ovs_translate_actions(&pkey, flow->of_list_action, reply, OVS_PACKET_ATTR_ACTIONS); nla_put(reply, OVS_PACKET_ATTR_KEY, nla_len(key), nla_data(key)); nla_put(reply, OVS_PACKET_ATTR_PACKET, nla_len(packet), nla_data(packet)); struct nlattr *actions = nlmsg_find_attr(nlmsg_hdr(reply), sizeof(struct genlmsghdr) + sizeof(struct ovs_header), OVS_PACKET_ATTR_ACTIONS); /* Don't send the packet back out if it would be dropped. */ if (nla_len(actions) > 0) { nl_send_auto(port->notify_socket, reply); } ind_ovs_nlmsg_freelist_free(reply); }
void ind_ovs_port_added(uint32_t port_no, const char *ifname, of_mac_addr_t mac_addr) { indigo_error_t err; if (ind_ovs_ports[port_no]) { return; } struct ind_ovs_port *port = calloc(1, sizeof(*port)); if (port == NULL) { LOG_ERROR("failed to allocate port"); return; } strncpy(port->ifname, ifname, sizeof(port->ifname)); port->dp_port_no = port_no; port->mac_addr = mac_addr; aim_ratelimiter_init(&port->upcall_log_limiter, 1000*1000, 5, NULL); aim_ratelimiter_init(&port->pktin_limiter, PORT_PKTIN_INTERVAL, PORT_PKTIN_BURST_SIZE, NULL); pthread_mutex_init(&port->quiesce_lock, NULL); pthread_cond_init(&port->quiesce_cvar, NULL); port->notify_socket = ind_ovs_create_nlsock(); if (port->notify_socket == NULL) { goto cleanup_port; } if (nl_socket_set_nonblocking(port->notify_socket) < 0) { LOG_ERROR("failed to set netlink socket nonblocking"); goto cleanup_port; } struct nl_msg *msg = ind_ovs_create_nlmsg(ovs_vport_family, OVS_VPORT_CMD_SET); nla_put_u32(msg, OVS_VPORT_ATTR_PORT_NO, port_no); nla_put_u32(msg, OVS_VPORT_ATTR_UPCALL_PID, nl_socket_get_local_port(port->notify_socket)); err = ind_ovs_transact(msg); if (err < 0) { LOG_ERROR("datapath failed to configure port %s", ifname); goto cleanup_port; } if (!ind_ovs_get_interface_flags(ifname, &port->ifflags)) { /* Bring interface up if not already */ if (!(port->ifflags & IFF_UP)) { port->ifflags |= IFF_UP; (void) ind_ovs_set_interface_flags(ifname, port->ifflags); } } else { /* Not a netdev, fake the interface flags */ port->ifflags = IFF_UP; } /* Ensure port is fully populated before publishing it. */ __sync_synchronize(); ind_ovs_ports[port_no] = port; if ((err = port_status_notify(port_no, OF_PORT_CHANGE_REASON_ADD)) < 0) { LOG_WARN("failed to notify controller of port addition"); /* Can't cleanup the port because it's already visible to other * threads. */ } ind_ovs_upcall_register(port); LOG_INFO("Added port %s", port->ifname); ind_ovs_kflow_invalidate_all(); return; cleanup_port: assert(ind_ovs_ports[port_no] == NULL); if (port->notify_socket) { nl_socket_free(port->notify_socket); } free(port); }