<commit_before>/****************************************************************
 *
 *        Copyright 2014, 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 <dhcpra/dhcpra.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "dhcp.h"
#include "dhcpra_int.h"
#include "dhcpr_table.h"
#include "dhcrelay.h"

#include <indigo/of_state_manager.h>
#include <OS/os.h>
#include <SocketManager/socketmanager.h>
#include <PPE/ppe.h>


dhcp_relay_stat_t dhcp_stat_ports[MAX_SYSTEM_PORT+1];

/* This variable is set by ucli for debugging purpose*/
int dhcpra_dump_data = DHCPRA_DUMP_DISABLE_ALL_PORTS;

/* Maximum DHCP packet out */
#define OUT_PKT_BUF_SIZE DHCP_MTU_MAX

/* Maximum hop count */
static int max_hop_count = 10;

static aim_ratelimiter_t dhcpra_pktin_log_limiter;

/*
 * NOTE: We can call ppe_build_ipv4_header to build ip header by
 *       providing sub protocol such UDP, ICMP, TCP, then DHCP
 * However, we have to do parsing couple times to recognize sub protocols
 * It is simple and fast to fill packet directly
 * Then we call parsing one time only for legality check and filling checksum
 */
struct ip {
    uint8_t  ip_fvhl; /* header length, version: Default 0x45 */
    uint8_t  ip_tos;  /* type of service: IPTOS_LOWDELAY */
    uint16_t ip_len;  /* total length: ip_hdr + payload(udp + payload): User */
    uint16_t ip_id;   /* identification: 0*/
    uint16_t ip_off;  /* fragment offset field: 0 */
    uint8_t  ip_ttl;  /* time to live: 128 */
    uint8_t  ip_p;    /* protocol: UDP */
    uint16_t ip_sum;  /* checksum: User */
    struct in_addr ip_src, ip_dst; /* source and dest address: User */
};

struct udp {
    u_int16_t uh_sport;     /* source port - 0 */
    u_int16_t uh_dport;     /* destination port - User */
    u_int16_t uh_ulen;      /* udp length: udp_hdr + payload - User */
    u_int16_t uh_sum;       /* udp checksum - User*/
};

#define ETHERTYPE_DOT1Q 0x8100
#define DOT1Q_IP_HEADER_OFFSET 18
#define UDP_HEADER_OFFSET      (DOT1Q_IP_HEADER_OFFSET + sizeof(struct ip))
#define DHCP_HEADER_OFFSET     (UDP_HEADER_OFFSET + sizeof(struct udp))

#define SYSTEM_VLAN 4094

#define HEX_LEN 80
#define PER_LINE 16
static inline void
dhcpra_pkt_hexdump(unsigned char *buf, int bytes)
{
    int idx;
    char display[HEX_LEN];
    int disp_offset = 0;
    int buf_offset = 0;

    /*one byte is printed into 2 chars, extra byte for NULL char*/
    char whole_pkt_display[OUT_PKT_BUF_SIZE*2+1];
    int pkt_offset = 0;

    DHCPRA_DEBUG("DHCPRA_PKT_HEXDUMP");

    /* Legality check */
    if (bytes > OUT_PKT_BUF_SIZE) {
        DHCPRA_DEBUG("bytes_to_read=%d, pkt_offset=%d, display_size=%d",
                      bytes, pkt_offset, sizeof(whole_pkt_display));
        return;
    }

    /* Dump 16 bytes for quick view */
    while (bytes > 0) {

        disp_offset = 0;
        for (idx = 0; (idx < PER_LINE) && (idx < bytes); idx++) {

            /* aim_snprintf: only return number of chars, excluding null */
            disp_offset += aim_snprintf(&display[disp_offset], sizeof("xx"),
                                        "%02x", buf[buf_offset + idx]);

            pkt_offset += aim_snprintf(&whole_pkt_display[pkt_offset], sizeof("xx"),
                                       "%02x", buf[buf_offset + idx]);
        }

        DHCPRA_DEBUG("%s",display);

        bytes -= idx;
        buf_offset += idx;


    }

    /* Dump the whole packet at once for external tool analysis */
    DHCPRA_DEBUG("%s", whole_pkt_display);

}

static void
set_dot1q_ipv4_type (uint8_t *pkt)
{
    /* Set dot1q */
    pkt[12] = ETHERTYPE_DOT1Q >> 8;
    pkt[13] = ETHERTYPE_DOT1Q & 0xFF;

    /* Set ipv4 type */
    pkt[16] = PPE_ETHERTYPE_IP4 >> 8;
    pkt[17] = PPE_ETHERTYPE_IP4 & 0xFF;
}

#define IPTOS_LOWDELAY      0x10
#define IPTOS_THROUGHPUT    0x08
#define IPTOS_RELIABILITY   0x04
static void
set_ipv4_proto_type (uint8_t *pkt, int dhcp_len)
{
    struct ip *ip = (struct ip*)(pkt + DOT1Q_IP_HEADER_OFFSET);
    ip->ip_fvhl   = 0x45; /* Type 4, len 5 words */
    ip->ip_tos    = IPTOS_LOWDELAY;
    ip->ip_len    = htons(sizeof(struct ip) + sizeof(struct udp) + dhcp_len);
    ip->ip_id     = 0;
    ip->ip_off    = 0;
    ip->ip_ttl    = 128;
    ip->ip_p      = IPPROTO_UDP; /* 17 */
    /* check sum, ip addr will be set later */
}

static void
set_udp_port (uint8_t *pkt, u_int16_t dhcp_len, u_int16_t sport, u_int16_t dport)
{
    struct udp *udp = (struct udp*) (pkt + UDP_HEADER_OFFSET);
    udp->uh_sport   = htons(sport);
    udp->uh_dport   = htons(dport);
    udp->uh_ulen    = htons(sizeof(struct udp) + dhcp_len);
    /* check sum will be set later using ppe_packet_update */
}

static void
init_ppe_header (uint8_t *pkt, uint32_t dhcp_len, uint32_t sport, uint32_t dport)
{
    set_dot1q_ipv4_type (pkt);
    set_ipv4_proto_type (pkt, dhcp_len);
    set_udp_port (pkt, dhcp_len, sport, dport);
}

static void
dhcpra_send_pkt (of_octets_t *octets, of_port_no_t port_no)
{
    of_packet_out_t    *pkt_out;
    of_list_action_t   *list;
    of_action_output_t *action;
    int                rv;

     /* Always use OF_VERSION_1_3 */
    uint32_t version  = OF_VERSION_1_3;
    uint32_t out_port = OF_PORT_DEST_USE_TABLE; /* (0xfffffff9) OFPP_TABLE */
    uint32_t in_port  = OF_PORT_DEST_LOCAL;

    pkt_out = of_packet_out_new (version);
    if(!pkt_out){
        AIM_LOG_ERROR("Failed to allocate packet out");
        return;
    }
    of_packet_out_buffer_id_set(pkt_out, -1);
    of_packet_out_in_port_set(pkt_out, in_port);

    action = of_action_output_new(version);
    if(!action){
        of_packet_out_delete(pkt_out);
        AIM_LOG_ERROR("Failed to allocation action");
        return;
    }
    of_action_output_port_set(action, out_port);

    list = of_list_action_new(version);
    if(!list){
        of_packet_out_delete(pkt_out);
        of_object_delete(action);
        AIM_LOG_ERROR("Failed to allocate action list");
        return;
    }

    of_list_append(list, action);
    of_object_delete(action);

    rv = of_packet_out_actions_set(pkt_out, list);
    AIM_TRUE_OR_DIE(rv==OF_ERROR_NONE);
<commit_msg>dhcpra: send packets from OFPP_CONTROLLER instead of OFPP_LOCAL<commit_after>/****************************************************************
 *
 *        Copyright 2014, 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 <dhcpra/dhcpra.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "dhcp.h"
#include "dhcpra_int.h"
#include "dhcpr_table.h"
#include "dhcrelay.h"

#include <indigo/of_state_manager.h>
#include <OS/os.h>
#include <SocketManager/socketmanager.h>
#include <PPE/ppe.h>


dhcp_relay_stat_t dhcp_stat_ports[MAX_SYSTEM_PORT+1];

/* This variable is set by ucli for debugging purpose*/
int dhcpra_dump_data = DHCPRA_DUMP_DISABLE_ALL_PORTS;

/* Maximum DHCP packet out */
#define OUT_PKT_BUF_SIZE DHCP_MTU_MAX

/* Maximum hop count */
static int max_hop_count = 10;

static aim_ratelimiter_t dhcpra_pktin_log_limiter;

/*
 * NOTE: We can call ppe_build_ipv4_header to build ip header by
 *       providing sub protocol such UDP, ICMP, TCP, then DHCP
 * However, we have to do parsing couple times to recognize sub protocols
 * It is simple and fast to fill packet directly
 * Then we call parsing one time only for legality check and filling checksum
 */
struct ip {
    uint8_t  ip_fvhl; /* header length, version: Default 0x45 */
    uint8_t  ip_tos;  /* type of service: IPTOS_LOWDELAY */
    uint16_t ip_len;  /* total length: ip_hdr + payload(udp + payload): User */
    uint16_t ip_id;   /* identification: 0*/
    uint16_t ip_off;  /* fragment offset field: 0 */
    uint8_t  ip_ttl;  /* time to live: 128 */
    uint8_t  ip_p;    /* protocol: UDP */
    uint16_t ip_sum;  /* checksum: User */
    struct in_addr ip_src, ip_dst; /* source and dest address: User */
};

struct udp {
    u_int16_t uh_sport;     /* source port - 0 */
    u_int16_t uh_dport;     /* destination port - User */
    u_int16_t uh_ulen;      /* udp length: udp_hdr + payload - User */
    u_int16_t uh_sum;       /* udp checksum - User*/
};

#define ETHERTYPE_DOT1Q 0x8100
#define DOT1Q_IP_HEADER_OFFSET 18
#define UDP_HEADER_OFFSET      (DOT1Q_IP_HEADER_OFFSET + sizeof(struct ip))
#define DHCP_HEADER_OFFSET     (UDP_HEADER_OFFSET + sizeof(struct udp))

#define SYSTEM_VLAN 4094

#define HEX_LEN 80
#define PER_LINE 16
static inline void
dhcpra_pkt_hexdump(unsigned char *buf, int bytes)
{
    int idx;
    char display[HEX_LEN];
    int disp_offset = 0;
    int buf_offset = 0;

    /*one byte is printed into 2 chars, extra byte for NULL char*/
    char whole_pkt_display[OUT_PKT_BUF_SIZE*2+1];
    int pkt_offset = 0;

    DHCPRA_DEBUG("DHCPRA_PKT_HEXDUMP");

    /* Legality check */
    if (bytes > OUT_PKT_BUF_SIZE) {
        DHCPRA_DEBUG("bytes_to_read=%d, pkt_offset=%d, display_size=%d",
                      bytes, pkt_offset, sizeof(whole_pkt_display));
        return;
    }

    /* Dump 16 bytes for quick view */
    while (bytes > 0) {

        disp_offset = 0;
        for (idx = 0; (idx < PER_LINE) && (idx < bytes); idx++) {

            /* aim_snprintf: only return number of chars, excluding null */
            disp_offset += aim_snprintf(&display[disp_offset], sizeof("xx"),
                                        "%02x", buf[buf_offset + idx]);

            pkt_offset += aim_snprintf(&whole_pkt_display[pkt_offset], sizeof("xx"),
                                       "%02x", buf[buf_offset + idx]);
        }

        DHCPRA_DEBUG("%s",display);

        bytes -= idx;
        buf_offset += idx;


    }

    /* Dump the whole packet at once for external tool analysis */
    DHCPRA_DEBUG("%s", whole_pkt_display);

}

static void
set_dot1q_ipv4_type (uint8_t *pkt)
{
    /* Set dot1q */
    pkt[12] = ETHERTYPE_DOT1Q >> 8;
    pkt[13] = ETHERTYPE_DOT1Q & 0xFF;

    /* Set ipv4 type */
    pkt[16] = PPE_ETHERTYPE_IP4 >> 8;
    pkt[17] = PPE_ETHERTYPE_IP4 & 0xFF;
}

#define IPTOS_LOWDELAY      0x10
#define IPTOS_THROUGHPUT    0x08
#define IPTOS_RELIABILITY   0x04
static void
set_ipv4_proto_type (uint8_t *pkt, int dhcp_len)
{
    struct ip *ip = (struct ip*)(pkt + DOT1Q_IP_HEADER_OFFSET);
    ip->ip_fvhl   = 0x45; /* Type 4, len 5 words */
    ip->ip_tos    = IPTOS_LOWDELAY;
    ip->ip_len    = htons(sizeof(struct ip) + sizeof(struct udp) + dhcp_len);
    ip->ip_id     = 0;
    ip->ip_off    = 0;
    ip->ip_ttl    = 128;
    ip->ip_p      = IPPROTO_UDP; /* 17 */
    /* check sum, ip addr will be set later */
}

static void
set_udp_port (uint8_t *pkt, u_int16_t dhcp_len, u_int16_t sport, u_int16_t dport)
{
    struct udp *udp = (struct udp*) (pkt + UDP_HEADER_OFFSET);
    udp->uh_sport   = htons(sport);
    udp->uh_dport   = htons(dport);
    udp->uh_ulen    = htons(sizeof(struct udp) + dhcp_len);
    /* check sum will be set later using ppe_packet_update */
}

static void
init_ppe_header (uint8_t *pkt, uint32_t dhcp_len, uint32_t sport, uint32_t dport)
{
    set_dot1q_ipv4_type (pkt);
    set_ipv4_proto_type (pkt, dhcp_len);
    set_udp_port (pkt, dhcp_len, sport, dport);
}

static void
dhcpra_send_pkt (of_octets_t *octets, of_port_no_t port_no)
{
    of_packet_out_t    *pkt_out;
    of_list_action_t   *list;
    of_action_output_t *action;
    int                rv;

     /* Always use OF_VERSION_1_3 */
    uint32_t version  = OF_VERSION_1_3;
    uint32_t out_port = OF_PORT_DEST_USE_TABLE; /* (0xfffffff9) OFPP_TABLE */
    uint32_t in_port  = OF_PORT_DEST_CONTROLLER;

    pkt_out = of_packet_out_new (version);
    if(!pkt_out){
        AIM_LOG_ERROR("Failed to allocate packet out");
        return;
    }
    of_packet_out_buffer_id_set(pkt_out, -1);
    of_packet_out_in_port_set(pkt_out, in_port);

    action = of_action_output_new(version);
    if(!action){
        of_packet_out_delete(pkt_out);
        AIM_LOG_ERROR("Failed to allocation action");
        return;
    }
    of_action_output_port_set(action, out_port);

    list = of_list_action_new(version);
    if(!list){
        of_packet_out_delete(pkt_out);
        of_object_delete(action);
        AIM_LOG_ERROR("Failed to allocate action list");
        return;
    }

    of_list_append(list, action);
    of_object_delete(action);

    rv = of_packet_out_actions_set(pkt_out, list);
    AIM_TRUE_OR_DIE(rv==OF_ERROR_NONE);

{'fraction_non_alphanumeric': 0.11992305985055855, 'fraction_numerical': 0.022046312051490716, 'mean_word_length': 3.1213414634146344, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6325424', 'n_tokens_mistral': 5067, 'n_tokens_neox': 4852, 'n_words': 1215}