<commit_before>/****************************************************************
 *
 *        Copyright 2013, Big Switch Networks, Inc.
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *        http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the
 * License.
 *
 ****************************************************************/

#include "ovs_driver_int.h"
#include "ovsdriver_log.h"
#include "indigo/forwarding.h"
#include "indigo/port_manager.h"
#include "indigo/of_state_manager.h"
#include "SocketManager/socketmanager.h"
#include <errno.h>
#include <netlink/cache.h>
#include <netlink/route/link.h>

#ifndef _LINUX_IF_H
/* Some versions of libnetlink include linux/if.h, which conflicts with net/if.h. */
#include <net/if.h>
#endif

struct ind_ovs_port *ind_ovs_ports[IND_OVS_MAX_PORTS];  /**< Table of all ports */

static struct nl_sock *route_cache_sock;
static struct nl_cache_mngr *route_cache_mngr;
static struct nl_cache *link_cache;
static struct nl_cb *netlink_callbacks;

static indigo_error_t port_status_notify(uint32_t port_no, unsigned reason);
static void port_desc_set(of_port_desc_t *of_port_desc, of_port_no_t of_port_num);
static void alloc_port_counters(struct ind_ovs_port_counters *pcounters);
static void free_port_counters(struct ind_ovs_port_counters *pcounters);
static uint64_t get_packet_stats(struct stats_handle *handle);

aim_ratelimiter_t nl_cache_refill_limiter;

static struct ind_ovs_port_counters dummy_stats;

static void
ind_ovs_update_link_stats()
{
    if (aim_ratelimiter_limit(&nl_cache_refill_limiter, monotonic_us()) == 0) {
        /* Refresh statistics */
        nl_cache_refill(route_cache_sock, link_cache);
    }
}

struct ind_ovs_port *
ind_ovs_port_lookup(of_port_no_t port_no)
{
    if (port_no == OF_PORT_DEST_LOCAL) {
        return ind_ovs_ports[OVSP_LOCAL];
    }

    if (port_no >= IND_OVS_MAX_PORTS) {
        return NULL;
    }

    return ind_ovs_ports[port_no];
}

struct ind_ovs_port *
ind_ovs_port_lookup_by_name(const char *ifname)
{
    int i;
    for (i = 0; i < IND_OVS_MAX_PORTS; i++) {
        struct ind_ovs_port *port = ind_ovs_ports[i];
        if (port && !strcmp(port->ifname, ifname)) {
            return port;
        }
    }
    return NULL;
}

uint32_t
ind_ovs_port_lookup_netlink(of_port_no_t port_no)
{
    struct ind_ovs_port *port = ind_ovs_port_lookup(port_no);
    if (port == NULL) {
        return 0;
    }

    return nl_socket_get_local_port(port->pktin_socket);
}

/* TODO populate more fields of the port desc */
indigo_error_t indigo_port_features_get(
    of_features_reply_t *features)
{
    indigo_error_t      result             = INDIGO_ERROR_NONE;
    of_list_port_desc_t *of_list_port_desc = 0;
    of_port_desc_t      *of_port_desc      = 0;

    if (features->version >= OF_VERSION_1_3) {
        return INDIGO_ERROR_NONE;
    }

    if ((of_port_desc = of_port_desc_new(features->version)) == 0) {
        LOG_ERROR("of_port_desc_new() failed");
        result = INDIGO_ERROR_UNKNOWN;
        goto done;
    }

    if ((of_list_port_desc = of_list_port_desc_new(features->version)) == 0) {
        LOG_ERROR("of_list_port_desc_new() failed");
        result = INDIGO_ERROR_UNKNOWN;
        goto done;
    }

    int i;
    for (i = 0; i < IND_OVS_MAX_PORTS; i++) {
        if (ind_ovs_ports[i]) {
            port_desc_set(of_port_desc, i);
            /* TODO error handling */
            of_list_port_desc_append(of_list_port_desc, of_port_desc);
        }
    }

    if (LOXI_FAILURE(of_features_reply_ports_set(features,
                                                 of_list_port_desc
                                                 )
                     )
        ) {
        LOG_ERROR("of_features_reply_ports_set() failed");
        result = INDIGO_ERROR_UNKNOWN;
        goto done;
    }

 done:
    if (of_list_port_desc)  of_list_port_desc_delete(of_list_port_desc);
    if (of_port_desc)       of_port_desc_delete(of_port_desc);

    return (result);
}

/*
 * 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);
}

indigo_error_t 
indigo_port_interface_list(indigo_port_info_t** list)
{
    int i;
    indigo_port_info_t* head = NULL; 

    if(list == NULL) { 
        return INDIGO_ERROR_PARAM; 
    }

    for (i = IND_OVS_MAX_PORTS-1; i >= 0; i--) { 
        struct ind_ovs_port *port = ind_ovs_ports[i];
        if(port != NULL) { 
            indigo_port_info_t* pi = aim_zmalloc(sizeof(*pi));
            strncpy(pi->port_name, port->ifname, sizeof(port->ifname)); 
            pi->of_port = i; 
            pi->next = head; 
            head = pi;
        }
    }<commit_msg>OVSDriver: allow adding a port without specifying the port number<commit_after>/****************************************************************
 *
 *        Copyright 2013, Big Switch Networks, Inc.
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *        http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the
 * License.
 *
 ****************************************************************/

#include "ovs_driver_int.h"
#include "ovsdriver_log.h"
#include "indigo/forwarding.h"
#include "indigo/port_manager.h"
#include "indigo/of_state_manager.h"
#include "SocketManager/socketmanager.h"
#include <errno.h>
#include <netlink/cache.h>
#include <netlink/route/link.h>

#ifndef _LINUX_IF_H
/* Some versions of libnetlink include linux/if.h, which conflicts with net/if.h. */
#include <net/if.h>
#endif

struct ind_ovs_port *ind_ovs_ports[IND_OVS_MAX_PORTS];  /**< Table of all ports */

static struct nl_sock *route_cache_sock;
static struct nl_cache_mngr *route_cache_mngr;
static struct nl_cache *link_cache;
static struct nl_cb *netlink_callbacks;

static indigo_error_t port_status_notify(uint32_t port_no, unsigned reason);
static void port_desc_set(of_port_desc_t *of_port_desc, of_port_no_t of_port_num);
static void alloc_port_counters(struct ind_ovs_port_counters *pcounters);
static void free_port_counters(struct ind_ovs_port_counters *pcounters);
static uint64_t get_packet_stats(struct stats_handle *handle);

aim_ratelimiter_t nl_cache_refill_limiter;

static struct ind_ovs_port_counters dummy_stats;

static void
ind_ovs_update_link_stats()
{
    if (aim_ratelimiter_limit(&nl_cache_refill_limiter, monotonic_us()) == 0) {
        /* Refresh statistics */
        nl_cache_refill(route_cache_sock, link_cache);
    }
}

struct ind_ovs_port *
ind_ovs_port_lookup(of_port_no_t port_no)
{
    if (port_no == OF_PORT_DEST_LOCAL) {
        return ind_ovs_ports[OVSP_LOCAL];
    }

    if (port_no >= IND_OVS_MAX_PORTS) {
        return NULL;
    }

    return ind_ovs_ports[port_no];
}

struct ind_ovs_port *
ind_ovs_port_lookup_by_name(const char *ifname)
{
    int i;
    for (i = 0; i < IND_OVS_MAX_PORTS; i++) {
        struct ind_ovs_port *port = ind_ovs_ports[i];
        if (port && !strcmp(port->ifname, ifname)) {
            return port;
        }
    }
    return NULL;
}

uint32_t
ind_ovs_port_lookup_netlink(of_port_no_t port_no)
{
    struct ind_ovs_port *port = ind_ovs_port_lookup(port_no);
    if (port == NULL) {
        return 0;
    }

    return nl_socket_get_local_port(port->pktin_socket);
}

/* TODO populate more fields of the port desc */
indigo_error_t indigo_port_features_get(
    of_features_reply_t *features)
{
    indigo_error_t      result             = INDIGO_ERROR_NONE;
    of_list_port_desc_t *of_list_port_desc = 0;
    of_port_desc_t      *of_port_desc      = 0;

    if (features->version >= OF_VERSION_1_3) {
        return INDIGO_ERROR_NONE;
    }

    if ((of_port_desc = of_port_desc_new(features->version)) == 0) {
        LOG_ERROR("of_port_desc_new() failed");
        result = INDIGO_ERROR_UNKNOWN;
        goto done;
    }

    if ((of_list_port_desc = of_list_port_desc_new(features->version)) == 0) {
        LOG_ERROR("of_list_port_desc_new() failed");
        result = INDIGO_ERROR_UNKNOWN;
        goto done;
    }

    int i;
    for (i = 0; i < IND_OVS_MAX_PORTS; i++) {
        if (ind_ovs_ports[i]) {
            port_desc_set(of_port_desc, i);
            /* TODO error handling */
            of_list_port_desc_append(of_list_port_desc, of_port_desc);
        }
    }

    if (LOXI_FAILURE(of_features_reply_ports_set(features,
                                                 of_list_port_desc
                                                 )
                     )
        ) {
        LOG_ERROR("of_features_reply_ports_set() failed");
        result = INDIGO_ERROR_UNKNOWN;
        goto done;
    }

 done:
    if (of_list_port_desc)  of_list_port_desc_delete(of_list_port_desc);
    if (of_port_desc)       of_port_desc_delete(of_port_desc);

    return (result);
}

/*
 * 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 || of_port == OF_PORT_DEST_NONE);
    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);
    if (of_port != OF_PORT_DEST_NONE) {
        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);
}

indigo_error_t 
indigo_port_interface_list(indigo_port_info_t** list)
{
    int i;
    indigo_port_info_t* head = NULL; 

    if(list == NULL) { 
        return INDIGO_ERROR_PARAM; 
    }

    for (i = IND_OVS_MAX_PORTS-1; i >= 0; i--) { 
        struct ind_ovs_port *port = ind_ovs_ports[i];
        if(port != NULL) { 
            indigo_port_info_t* pi = aim_zmalloc(sizeof(*pi));
            strncpy(pi->port_name, port->ifname, sizeof(port->ifname)); 
            pi->of_port = i; 
            pi->next = head; 
            head = pi;
        }
    }
{'fraction_non_alphanumeric': 0.11021823718490949, 'fraction_numerical': 0.0060903400439857895, 'mean_word_length': 3.330769230769231, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1670863', 'n_tokens_mistral': 4265, 'n_tokens_neox': 4145, 'n_words': 876}