Ejemplo n.º 1
0
/*
 * arpra_parse_packet
 * 
 * Parse ARP packet and extract info 
 */
static indigo_error_t
arpra_parse_packet (ppe_packet_t *ppep, arp_info_t *info, bool vlan_tagged)
{
    uint32_t tmp;    

    if (!ppep || !info) return INDIGO_ERROR_PARAM;

    ppe_wide_field_get(ppep, PPE_FIELD_ETHERNET_DST_MAC, info->eth_dst.addr);

    ppe_wide_field_get(ppep, PPE_FIELD_ETHERNET_SRC_MAC, info->eth_src.addr);

    if (vlan_tagged) {
        ppe_field_get(ppep, PPE_FIELD_8021Q_VLAN, &tmp);
        info->vlan_vid = tmp;

        ppe_field_get(ppep, PPE_FIELD_8021Q_PRI, &tmp);
        info->vlan_pcp = tmp;
    }

    ppe_field_get(ppep, PPE_FIELD_ARP_HTYPE, &tmp);
    if (tmp != 1) {
        return INDIGO_ERROR_PARSE;
    }

    ppe_field_get(ppep, PPE_FIELD_ARP_PTYPE, &tmp);
    if (tmp != 0x0800) {
        return INDIGO_ERROR_PARSE;
    }

    ppe_field_get(ppep, PPE_FIELD_ARP_HLEN, &tmp);
    if (tmp != 6) {
        return INDIGO_ERROR_PARSE;
    }

    ppe_field_get(ppep, PPE_FIELD_ARP_PLEN, &tmp);
    if (tmp != 4) {
        return INDIGO_ERROR_PARSE;
    }

    ppe_field_get(ppep, PPE_FIELD_ARP_OPERATION, &tmp);
    info->operation = tmp;

    ppe_wide_field_get(ppep, PPE_FIELD_ARP_SHA, info->sender.mac.addr);

    ppe_field_get(ppep, PPE_FIELD_ARP_SPA, &tmp);
    info->sender.ipv4 = tmp;

    ppe_wide_field_get(ppep, PPE_FIELD_ARP_THA, info->target.mac.addr);

    ppe_field_get(ppep, PPE_FIELD_ARP_TPA, &tmp);
    info->target.ipv4 = tmp;

    return INDIGO_ERROR_NONE;
}
Ejemplo n.º 2
0
void
icmpa_verify_packet (of_octets_t *octets, uint32_t reason)
{
    ppe_packet_t               ppep;
    uint32_t                   icmp_type;

    if (!octets) return;

    ppe_packet_init(&ppep, octets->data, octets->bytes);    
    if (ppe_parse(&ppep) < 0) {
        AIM_LOG_ERROR("Packet_in parsing failed.");
        return;
    }

    assert(ppe_header_get(&ppep, PPE_HEADER_ICMP)); 
    ppe_field_get(&ppep, PPE_FIELD_ICMP_TYPE, &icmp_type);
    assert(icmp_type == reason); 
}
Ejemplo n.º 3
0
static ucli_status_t
ppe_ucli_utm__fdump__(ucli_context_t* uc)
{
    ppe_field_t field; 
    ppe_header_t format; 
    

    UCLI_COMMAND_INFO(uc, 
                      "fdump", 0, 
                      "Dump all packet fields."); 

    ppe_packet_format_get(&ppec->ppep, &format); 
    ucli_printf(uc, "format=%{ppe_header}, size=%d\n", 
                format, ppec->ppep.size); 
    
    for(field = 0; field < PPE_FIELD_COUNT; field++) {
        const ppe_field_info_t* fi = ppe_field_info_get(field); 

        if(fi->size_bits == 0) {
            continue; 
        }
        if(ppe_field_exists(&ppec->ppep, field) == 0) {
            continue; 
        }

        if(fi->size_bits <= 32) {
            uint32_t data; 
            ppe_field_get(&ppec->ppep, field, &data); 
            ucli_printf(uc, "%{ppe_field} = 0x%x (%d)\n", 
                        field, data, data); 
        }
        else {
            uint8_t* p = ppe_fieldp_get(&ppec->ppep, field);
            ucli_printf(uc, "%{ppe_field} = %{data}\n", field, 
                        p, fi->size_bits/8); 
        }
    }
    return UCLI_STATUS_OK; 
}
Ejemplo n.º 4
0
static ucli_status_t
ppe_ucli_utm__rwall__(ucli_context_t* uc)
{
    ppe_packet_t ppep;  
    ppe_header_t header; 
    ppe_field_t f; 
    int rv = UCLI_STATUS_OK; 

    UCLI_COMMAND_INFO(uc, 
                      "rwall", 0, 
                      "Read and write all packet fields in all headers."); 

    ppe_packet_init(&ppep, NULL, 0);

    /**
     * Allocate and assign a header pointer for every header type. 
     * All bits will be initialized to 1. 
     */
    for(header = 0; header < PPE_HEADER_COUNT; header++) {
        uint8_t* hp = aim_zmalloc(1000); 
        PPE_MEMSET(hp, 0xFF, 1000); 
        ppe_header_set(&ppep, header, hp); 
    }

    /**
     * Check that every field reads back as all 1's, with the correct width
     */
    for(f = 0; f < PPE_FIELD_COUNT; f++) {
        const ppe_field_info_t* fi = ppe_field_info_get(f); 
        if(fi->size_bits == 0) { 
            continue; 
        }
        if(fi->size_bits <= 32) {
            uint32_t v;
            ppe_field_get(&ppep, f, &v); 
            if(fi->size_bits == 32) {
                if(v != 0xFFFFFFFF)  {
                    rv = ucli_error(uc, "first read: field %{ppe_field} is 0x%x, should be 0x%x", 
                                    f, v, -1); 
                }
            }
            else {
                if(v != ( (1U << fi->size_bits) - 1)) { 
                    rv = ucli_error(uc, "first read: field %{ppe_field} is 0x%x, should be 0x%x (%d bits)", 
                                    f, v, (1<<fi->size_bits) - 1, fi->size_bits); 
                }
            }
            /** clear field and re-read */
            ppe_field_set(&ppep, f, 0); 
            ppe_field_get(&ppep, f, &v); 
            if(v != 0) {
                rv = ucli_error(uc, "second read: field %{ppe_field} is 0x%x when it should be 0.", 
                                f, v); 
            }            
        }
        else {
            uint8_t vb[64];    
            int bytes = ppe_wide_field_get(&ppep, f, vb); 
            int i; 
            for(i = 0; i < bytes; i++) {
                if(vb[i] != 0xFF) { 
                    rv = ucli_error(uc, "first read: field %{ppe_field}[%d] is 0x%.2x, should be 0x%.2x", 
                                    f, i, vb[i], 0xFF); 
                }
            }
            PPE_MEMSET(vb, 0, sizeof(vb)); 
            /** clear field and re-read */
            ppe_wide_field_set(&ppep, f, vb); 
            PPE_MEMSET(vb, 0xFF, sizeof(vb)); 
            ppe_wide_field_get(&ppep, f, vb); 
            for(i = 0; i < bytes; i++) {
                if(vb[i] != 0) {
                    rv = ucli_error(uc, "second read: field %{ppe_field}[%d] is 0x%.2x, should be 0.", 
                                    f, i, vb[i]); 
                }
            }
        }

        /** continue reading other fields, making sure the field we just cleared
         * does not change the value of fields we have not yet visited. */

    }

    for(header = 0; header < PPE_HEADER_COUNT; header++) {
        aim_free(ppe_header_get(&ppep, header)); 
    }
    return rv; 
}
Ejemplo n.º 5
0
static ucli_status_t
ppe_ucli_utm__dfk__(ucli_context_t* uc)
{
    ppe_dfk_t dfk; 
    ppe_field_t fields[4]; 
    uint8_t* verify_data;
    unsigned int verify_data_size; 
    int rv = UCLI_STATUS_OK; 
    unsigned int i; 

    UCLI_COMMAND_INFO(uc, 
                      "dfk", AIM_ARRAYSIZE(fields)+1, 
                      "Generate and verify a dynamic field key."); 
    UCLI_ARGPARSE_OR_RETURN(uc, 
                            "{ppe_field}{ppe_field}{ppe_field}{ppe_field}{data}", 
                            fields+0, fields+1, fields+2, fields+3, 
                            &verify_data, &verify_data_size); 

    ppe_dfk_init(&dfk, fields, AIM_ARRAYSIZE(fields)); 
    i = ppe_packet_dfk(&ppec->ppep, &dfk); 

    if(i != verify_data_size) { 
        rv = ucli_error(uc, "dfk size is %d, verify data size is %d", 
                        i, verify_data_size); 
        goto dfk_error;
    }

    for(i = 0; i < AIM_ARRAYSIZE(fields); i++) {
        const ppe_field_info_t* fi = ppe_field_info_get(fields[i]); 
        int exists = ppe_field_exists(&ppec->ppep, fi->field); 
        if(exists && ( (dfk.mask & (1<<i)) == 0)) { 
            /* Should be in the field key but isn't.*/
            rv = ucli_error(uc, "%{ppe_field} exists in packet but not in field key.", 
                            fi->field);
            goto dfk_error; 
        }
        if(!(exists) && (dfk.mask & (1<<i))) { 
            /* Should not be in the field key but is. */
            rv = ucli_error(uc, "%{ppe_field} is in the key but not the packet.", 
                            fi->field); 
            goto dfk_error; 
        }
        
    }
    for(i = 0; i < verify_data_size; i++) { 
        if(verify_data[i] != dfk.data[i]) { 
            rv = ucli_error(uc, "key data mismatch at byte %d.\nkey=%{data}, verify=%{data}", 
                            i, dfk.data, verify_data_size, verify_data, verify_data_size);         
            goto dfk_error; 
        }
    }
    for(i = 0; i < AIM_ARRAYSIZE(fields); i++) {
        if(dfk.mask & (1<<i)) {         
            const ppe_field_info_t* fi = ppe_field_info_get(fields[i]); 
            if(fi->size_bits <= 32) { 
                uint32_t pdata;
                uint32_t kdata; 
                ppe_field_get(&ppec->ppep, fi->field, &pdata); 
                ppe_dfk_field_get(&dfk, fi->field, &kdata); 
                if(pdata != kdata) { 
                    rv = ucli_error(uc, "field_get mismatch: p=0x%x, k=0x%x"); 
                    goto dfk_error; 
                }
            }
            else { 
                unsigned int i; 
                uint8_t pdata[128]; 
                uint8_t kdata[128]; 
                
                ppe_wide_field_get(&ppec->ppep, fi->field, pdata); 
                ppe_dfk_wide_field_get(&dfk, fi->field, kdata); 
                for(i = 0; i < fi->size_bits/8; i++) { 
                    if(pdata[i] != kdata[i]) { 
                        rv = ucli_error(uc, "wide_field_get mismatch @ %d: p=0x%x k=0x%x", 
                                        i, pdata[i], kdata[i]); 
                        goto dfk_error; 
                    }
                }
            }
        }
    }

    aim_free(verify_data); 
    ppe_dfk_destroy(&dfk); 
    return UCLI_STATUS_OK; 

 dfk_error:
    ucli_printf(uc, "key: "); 
    ppe_dfk_show(&dfk, &uc->pvs); 
    ppe_dfk_destroy(&dfk); 
    aim_free(verify_data); 
    ucli_printf(uc, "\n"); 
    return rv; 
}
Ejemplo n.º 6
0
/*
 * icmp_packet_in_handler
 *
 * API for handling incoming packets
 */
indigo_core_listener_result_t
icmpa_packet_in_handler (of_packet_in_t *packet_in)
{
    of_octets_t                octets;
    of_port_no_t               port_no;
    of_match_t                 match;
    ppe_packet_t               ppep;
    indigo_core_listener_result_t result = INDIGO_CORE_LISTENER_RESULT_PASS;
    uint32_t                   type, code;

    debug_counter_inc(&pkt_counters.icmp_total_in_packets);
    if (!packet_in) return INDIGO_CORE_LISTENER_RESULT_PASS;

    of_packet_in_data_get(packet_in, &octets);

    /*
     * Identify the recv port
     */
    if (packet_in->version <= OF_VERSION_1_1) {
        return INDIGO_CORE_LISTENER_RESULT_PASS;
    } else {
        if (of_packet_in_match_get(packet_in, &match) < 0) {
            AIM_LOG_ERROR("ICMPA: match get failed");
            debug_counter_inc(&pkt_counters.icmp_internal_errors);
            return INDIGO_CORE_LISTENER_RESULT_PASS;
        }
        port_no = match.fields.in_port;
    }

    if (port_no == OF_PORT_DEST_CONTROLLER) {
        debug_counter_inc(&pkt_counters.icmp_total_passed_packets);
        return INDIGO_CORE_LISTENER_RESULT_PASS;
    }

    if (port_no > MAX_PORTS) {
        AIM_LOG_ERROR("ICMPA: Port No: %d Out of Range %d", port_no, MAX_PORTS);
        debug_counter_inc(&pkt_counters.icmp_internal_errors);
        return INDIGO_CORE_LISTENER_RESULT_PASS;
    }

    /*
     * Check the packet-in reasons in metadata
     *
     * Icmp agent should not consume packets coming in due to L2 Src miss
     * and Station Move.
     */
    if ((match.fields.metadata & OFP_BSN_PKTIN_FLAG_STATION_MOVE) ||
        (match.fields.metadata & OFP_BSN_PKTIN_FLAG_NEW_HOST)) {
        debug_counter_inc(&pkt_counters.icmp_total_passed_packets);
        return INDIGO_CORE_LISTENER_RESULT_PASS;
    }

    ppe_packet_init(&ppep, octets.data, octets.bytes);
    if (ppe_parse(&ppep) < 0) {
        AIM_LOG_RL_ERROR(&icmp_pktin_log_limiter, os_time_monotonic(),
                         "ICMPA: Packet_in parsing failed.");
        debug_counter_inc(&pkt_counters.icmp_internal_errors);
        return INDIGO_CORE_LISTENER_RESULT_PASS;
    }

    /*
     * Identify if this is an Echo Request, destined to one of VRouter
     */
    if (ppe_header_get(&ppep, PPE_HEADER_ICMP)) {
        if (icmpa_reply(&ppep, port_no, &result)) {
            ++port_pkt_counters[port_no].icmp_echo_packets;
            return result;
        }
    }

    /*
     * To handle traceroute, we need to check for
     * a) UDP Packet
     * b) dest IP is Vrouter IP
     * c) UDP src and dest ports are ephemeral
     */
    if (ppe_header_get(&ppep, PPE_HEADER_UDP) &&
        ppe_header_get(&ppep, PPE_HEADER_IP4)) {
        uint32_t dest_ip, src_port, dest_port;
        ppe_field_get(&ppep, PPE_FIELD_IP4_DST_ADDR, &dest_ip);
        ppe_field_get(&ppep, PPE_FIELD_UDP_SRC_PORT, &src_port);
        ppe_field_get(&ppep, PPE_FIELD_UDP_DST_PORT, &dest_port);

        if (router_ip_check(dest_ip) && is_ephemeral(src_port) &&
            is_ephemeral(dest_port)) {
            AIM_LOG_TRACE("ICMP Port Unreachable received on port: %d",
                          port_no);
            type = ICMP_DEST_UNREACHABLE;
            code = 3;
            result = INDIGO_CORE_LISTENER_RESULT_DROP;
            if (icmpa_send(&ppep, port_no, type, code)) {
                ++port_pkt_counters[port_no].icmp_port_unreachable_packets;
                return result;
            }
        }
    }

    /*
     * Identify if the reason is valid for ICMP Agent to consume the packet
     */
    if (match.fields.metadata & OFP_BSN_PKTIN_FLAG_L3_MISS) {
        AIM_LOG_TRACE("ICMP Dest Network Unreachable received on port: %d",
                      port_no);
        type = ICMP_DEST_UNREACHABLE;
        code = 0;
        result = INDIGO_CORE_LISTENER_RESULT_DROP;
        if (icmpa_send(&ppep, port_no, type, code)) {
            ++port_pkt_counters[port_no].icmp_net_unreachable_packets;
        }
    } else if (match.fields.metadata & OFP_BSN_PKTIN_FLAG_TTL_EXPIRED) {
        AIM_LOG_TRACE("ICMP TTL Expired received on port: %d", port_no);
        type = ICMP_TIME_EXCEEDED;
        code = 0;
        result = INDIGO_CORE_LISTENER_RESULT_DROP;
        if (icmpa_send(&ppep, port_no, type, code)) {
            ++port_pkt_counters[port_no].icmp_time_exceeded_packets;
        }
    }

    return result;
}