cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

rocker_of_dpa.c (81383B)


      1/*
      2 * QEMU rocker switch emulation - OF-DPA flow processing support
      3 *
      4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     14 * GNU General Public License for more details.
     15 */
     16
     17#include "qemu/osdep.h"
     18#include "net/eth.h"
     19#include "qapi/error.h"
     20#include "qapi/qapi-commands-rocker.h"
     21#include "qemu/iov.h"
     22#include "qemu/timer.h"
     23
     24#include "rocker.h"
     25#include "rocker_hw.h"
     26#include "rocker_fp.h"
     27#include "rocker_tlv.h"
     28#include "rocker_world.h"
     29#include "rocker_desc.h"
     30#include "rocker_of_dpa.h"
     31
     32static const MACAddr zero_mac = { .a = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
     33static const MACAddr ff_mac =   { .a = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
     34
     35typedef struct of_dpa {
     36    World *world;
     37    GHashTable *flow_tbl;
     38    GHashTable *group_tbl;
     39    unsigned int flow_tbl_max_size;
     40    unsigned int group_tbl_max_size;
     41} OfDpa;
     42
     43/* flow_key stolen mostly from OVS
     44 *
     45 * Note: fields that compare with network packet header fields
     46 * are stored in network order (BE) to avoid per-packet field
     47 * byte-swaps.
     48 */
     49
     50typedef struct of_dpa_flow_key {
     51    uint32_t in_pport;               /* ingress port */
     52    uint32_t tunnel_id;              /* overlay tunnel id */
     53    uint32_t tbl_id;                 /* table id */
     54    struct {
     55        __be16 vlan_id;              /* 0 if no VLAN */
     56        MACAddr src;                 /* ethernet source address */
     57        MACAddr dst;                 /* ethernet destination address */
     58        __be16 type;                 /* ethernet frame type */
     59    } eth;
     60    struct {
     61        uint8_t proto;               /* IP protocol or ARP opcode */
     62        uint8_t tos;                 /* IP ToS */
     63        uint8_t ttl;                 /* IP TTL/hop limit */
     64        uint8_t frag;                /* one of FRAG_TYPE_* */
     65    } ip;
     66    union {
     67        struct {
     68            struct {
     69                __be32 src;          /* IP source address */
     70                __be32 dst;          /* IP destination address */
     71            } addr;
     72            union {
     73                struct {
     74                    __be16 src;      /* TCP/UDP/SCTP source port */
     75                    __be16 dst;      /* TCP/UDP/SCTP destination port */
     76                    __be16 flags;    /* TCP flags */
     77                } tp;
     78                struct {
     79                    MACAddr sha;     /* ARP source hardware address */
     80                    MACAddr tha;     /* ARP target hardware address */
     81                } arp;
     82            };
     83        } ipv4;
     84        struct {
     85            struct {
     86                Ipv6Addr src;       /* IPv6 source address */
     87                Ipv6Addr dst;       /* IPv6 destination address */
     88            } addr;
     89            __be32 label;            /* IPv6 flow label */
     90            struct {
     91                __be16 src;          /* TCP/UDP/SCTP source port */
     92                __be16 dst;          /* TCP/UDP/SCTP destination port */
     93                __be16 flags;        /* TCP flags */
     94            } tp;
     95            struct {
     96                Ipv6Addr target;    /* ND target address */
     97                MACAddr sll;         /* ND source link layer address */
     98                MACAddr tll;         /* ND target link layer address */
     99            } nd;
    100        } ipv6;
    101    };
    102    int width;                       /* how many uint64_t's in key? */
    103} OfDpaFlowKey;
    104
    105/* Width of key which includes field 'f' in u64s, rounded up */
    106#define FLOW_KEY_WIDTH(f) \
    107    DIV_ROUND_UP(offsetof(OfDpaFlowKey, f) + sizeof_field(OfDpaFlowKey, f), \
    108    sizeof(uint64_t))
    109
    110typedef struct of_dpa_flow_action {
    111    uint32_t goto_tbl;
    112    struct {
    113        uint32_t group_id;
    114        uint32_t tun_log_lport;
    115        __be16 vlan_id;
    116    } write;
    117    struct {
    118        __be16 new_vlan_id;
    119        uint32_t out_pport;
    120        uint8_t copy_to_cpu;
    121        __be16 vlan_id;
    122    } apply;
    123} OfDpaFlowAction;
    124
    125typedef struct of_dpa_flow {
    126    uint32_t lpm;
    127    uint32_t priority;
    128    uint32_t hardtime;
    129    uint32_t idletime;
    130    uint64_t cookie;
    131    OfDpaFlowKey key;
    132    OfDpaFlowKey mask;
    133    OfDpaFlowAction action;
    134    struct {
    135        uint64_t hits;
    136        int64_t install_time;
    137        int64_t refresh_time;
    138        uint64_t rx_pkts;
    139        uint64_t tx_pkts;
    140    } stats;
    141} OfDpaFlow;
    142
    143typedef struct of_dpa_flow_pkt_fields {
    144    uint32_t tunnel_id;
    145    struct eth_header *ethhdr;
    146    __be16 *h_proto;
    147    struct vlan_header *vlanhdr;
    148    struct ip_header *ipv4hdr;
    149    struct ip6_header *ipv6hdr;
    150    Ipv6Addr *ipv6_src_addr;
    151    Ipv6Addr *ipv6_dst_addr;
    152} OfDpaFlowPktFields;
    153
    154typedef struct of_dpa_flow_context {
    155    uint32_t in_pport;
    156    uint32_t tunnel_id;
    157    struct iovec *iov;
    158    int iovcnt;
    159    struct eth_header ethhdr_rewrite;
    160    struct vlan_header vlanhdr_rewrite;
    161    struct vlan_header vlanhdr;
    162    OfDpa *of_dpa;
    163    OfDpaFlowPktFields fields;
    164    OfDpaFlowAction action_set;
    165} OfDpaFlowContext;
    166
    167typedef struct of_dpa_flow_match {
    168    OfDpaFlowKey value;
    169    OfDpaFlow *best;
    170} OfDpaFlowMatch;
    171
    172typedef struct of_dpa_group {
    173    uint32_t id;
    174    union {
    175        struct {
    176            uint32_t out_pport;
    177            uint8_t pop_vlan;
    178        } l2_interface;
    179        struct {
    180            uint32_t group_id;
    181            MACAddr src_mac;
    182            MACAddr dst_mac;
    183            __be16 vlan_id;
    184        } l2_rewrite;
    185        struct {
    186            uint16_t group_count;
    187            uint32_t *group_ids;
    188        } l2_flood;
    189        struct {
    190            uint32_t group_id;
    191            MACAddr src_mac;
    192            MACAddr dst_mac;
    193            __be16 vlan_id;
    194            uint8_t ttl_check;
    195        } l3_unicast;
    196    };
    197} OfDpaGroup;
    198
    199static int of_dpa_mask2prefix(__be32 mask)
    200{
    201    int i;
    202    int count = 32;
    203
    204    for (i = 0; i < 32; i++) {
    205        if (!(ntohl(mask) & ((2 << i) - 1))) {
    206            count--;
    207        }
    208    }
    209
    210    return count;
    211}
    212
    213#if defined(DEBUG_ROCKER)
    214static void of_dpa_flow_key_dump(OfDpaFlowKey *key, OfDpaFlowKey *mask)
    215{
    216    char buf[512], *b = buf, *mac;
    217
    218    b += sprintf(b, " tbl %2d", key->tbl_id);
    219
    220    if (key->in_pport || (mask && mask->in_pport)) {
    221        b += sprintf(b, " in_pport %2d", key->in_pport);
    222        if (mask && mask->in_pport != 0xffffffff) {
    223            b += sprintf(b, "/0x%08x", key->in_pport);
    224        }
    225    }
    226
    227    if (key->tunnel_id || (mask && mask->tunnel_id)) {
    228        b += sprintf(b, " tun %8d", key->tunnel_id);
    229        if (mask && mask->tunnel_id != 0xffffffff) {
    230            b += sprintf(b, "/0x%08x", key->tunnel_id);
    231        }
    232    }
    233
    234    if (key->eth.vlan_id || (mask && mask->eth.vlan_id)) {
    235        b += sprintf(b, " vlan %4d", ntohs(key->eth.vlan_id));
    236        if (mask && mask->eth.vlan_id != 0xffff) {
    237            b += sprintf(b, "/0x%04x", ntohs(key->eth.vlan_id));
    238        }
    239    }
    240
    241    if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) ||
    242        (mask && memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN))) {
    243        mac = qemu_mac_strdup_printf(key->eth.src.a);
    244        b += sprintf(b, " src %s", mac);
    245        g_free(mac);
    246        if (mask && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) {
    247            mac = qemu_mac_strdup_printf(mask->eth.src.a);
    248            b += sprintf(b, "/%s", mac);
    249            g_free(mac);
    250        }
    251    }
    252
    253    if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) ||
    254        (mask && memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN))) {
    255        mac = qemu_mac_strdup_printf(key->eth.dst.a);
    256        b += sprintf(b, " dst %s", mac);
    257        g_free(mac);
    258        if (mask && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) {
    259            mac = qemu_mac_strdup_printf(mask->eth.dst.a);
    260            b += sprintf(b, "/%s", mac);
    261            g_free(mac);
    262        }
    263    }
    264
    265    if (key->eth.type || (mask && mask->eth.type)) {
    266        b += sprintf(b, " type 0x%04x", ntohs(key->eth.type));
    267        if (mask && mask->eth.type != 0xffff) {
    268            b += sprintf(b, "/0x%04x", ntohs(mask->eth.type));
    269        }
    270        switch (ntohs(key->eth.type)) {
    271        case 0x0800:
    272        case 0x86dd:
    273            if (key->ip.proto || (mask && mask->ip.proto)) {
    274                b += sprintf(b, " ip proto %2d", key->ip.proto);
    275                if (mask && mask->ip.proto != 0xff) {
    276                    b += sprintf(b, "/0x%02x", mask->ip.proto);
    277                }
    278            }
    279            if (key->ip.tos || (mask && mask->ip.tos)) {
    280                b += sprintf(b, " ip tos %2d", key->ip.tos);
    281                if (mask && mask->ip.tos != 0xff) {
    282                    b += sprintf(b, "/0x%02x", mask->ip.tos);
    283                }
    284            }
    285            break;
    286        }
    287        switch (ntohs(key->eth.type)) {
    288        case 0x0800:
    289            if (key->ipv4.addr.dst || (mask && mask->ipv4.addr.dst)) {
    290                b += sprintf(b, " dst %s",
    291                    inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst));
    292                if (mask) {
    293                    b += sprintf(b, "/%d",
    294                                 of_dpa_mask2prefix(mask->ipv4.addr.dst));
    295                }
    296            }
    297            break;
    298        }
    299    }
    300
    301    DPRINTF("%s\n", buf);
    302}
    303#else
    304#define of_dpa_flow_key_dump(k, m)
    305#endif
    306
    307static void _of_dpa_flow_match(void *key, void *value, void *user_data)
    308{
    309    OfDpaFlow *flow = value;
    310    OfDpaFlowMatch *match = user_data;
    311    uint64_t *k = (uint64_t *)&flow->key;
    312    uint64_t *m = (uint64_t *)&flow->mask;
    313    uint64_t *v = (uint64_t *)&match->value;
    314    int i;
    315
    316    if (flow->key.tbl_id == match->value.tbl_id) {
    317        of_dpa_flow_key_dump(&flow->key, &flow->mask);
    318    }
    319
    320    if (flow->key.width > match->value.width) {
    321        return;
    322    }
    323
    324    for (i = 0; i < flow->key.width; i++, k++, m++, v++) {
    325        if ((~*k & *m & *v) | (*k & *m & ~*v)) {
    326            return;
    327        }
    328    }
    329
    330    DPRINTF("match\n");
    331
    332    if (!match->best ||
    333        flow->priority > match->best->priority ||
    334        flow->lpm > match->best->lpm) {
    335        match->best = flow;
    336    }
    337}
    338
    339static OfDpaFlow *of_dpa_flow_match(OfDpa *of_dpa, OfDpaFlowMatch *match)
    340{
    341    DPRINTF("\nnew search\n");
    342    of_dpa_flow_key_dump(&match->value, NULL);
    343
    344    g_hash_table_foreach(of_dpa->flow_tbl, _of_dpa_flow_match, match);
    345
    346    return match->best;
    347}
    348
    349static OfDpaFlow *of_dpa_flow_find(OfDpa *of_dpa, uint64_t cookie)
    350{
    351    return g_hash_table_lookup(of_dpa->flow_tbl, &cookie);
    352}
    353
    354static int of_dpa_flow_add(OfDpa *of_dpa, OfDpaFlow *flow)
    355{
    356    g_hash_table_insert(of_dpa->flow_tbl, &flow->cookie, flow);
    357
    358    return ROCKER_OK;
    359}
    360
    361static void of_dpa_flow_del(OfDpa *of_dpa, OfDpaFlow *flow)
    362{
    363    g_hash_table_remove(of_dpa->flow_tbl, &flow->cookie);
    364}
    365
    366static OfDpaFlow *of_dpa_flow_alloc(uint64_t cookie)
    367{
    368    OfDpaFlow *flow;
    369    int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
    370
    371    flow = g_new0(OfDpaFlow, 1);
    372
    373    flow->cookie = cookie;
    374    flow->mask.tbl_id = 0xffffffff;
    375
    376    flow->stats.install_time = flow->stats.refresh_time = now;
    377
    378    return flow;
    379}
    380
    381static void of_dpa_flow_pkt_hdr_reset(OfDpaFlowContext *fc)
    382{
    383    OfDpaFlowPktFields *fields = &fc->fields;
    384
    385    fc->iov[0].iov_base = fields->ethhdr;
    386    fc->iov[0].iov_len = sizeof(struct eth_header);
    387    fc->iov[1].iov_base = fields->vlanhdr;
    388    fc->iov[1].iov_len = fields->vlanhdr ? sizeof(struct vlan_header) : 0;
    389}
    390
    391static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc,
    392                                  const struct iovec *iov, int iovcnt)
    393{
    394    OfDpaFlowPktFields *fields = &fc->fields;
    395    size_t sofar = 0;
    396    int i;
    397
    398    sofar += sizeof(struct eth_header);
    399    if (iov->iov_len < sofar) {
    400        DPRINTF("flow_pkt_parse underrun on eth_header\n");
    401        return;
    402    }
    403
    404    fields->ethhdr = iov->iov_base;
    405    fields->h_proto = &fields->ethhdr->h_proto;
    406
    407    if (ntohs(*fields->h_proto) == ETH_P_VLAN) {
    408        sofar += sizeof(struct vlan_header);
    409        if (iov->iov_len < sofar) {
    410            DPRINTF("flow_pkt_parse underrun on vlan_header\n");
    411            return;
    412        }
    413        fields->vlanhdr = (struct vlan_header *)(fields->ethhdr + 1);
    414        fields->h_proto = &fields->vlanhdr->h_proto;
    415    }
    416
    417    switch (ntohs(*fields->h_proto)) {
    418    case ETH_P_IP:
    419        sofar += sizeof(struct ip_header);
    420        if (iov->iov_len < sofar) {
    421            DPRINTF("flow_pkt_parse underrun on ip_header\n");
    422            return;
    423        }
    424        fields->ipv4hdr = (struct ip_header *)(fields->h_proto + 1);
    425        break;
    426    case ETH_P_IPV6:
    427        sofar += sizeof(struct ip6_header);
    428        if (iov->iov_len < sofar) {
    429            DPRINTF("flow_pkt_parse underrun on ip6_header\n");
    430            return;
    431        }
    432        fields->ipv6hdr = (struct ip6_header *)(fields->h_proto + 1);
    433        break;
    434    }
    435
    436    /* To facilitate (potential) VLAN tag insertion, Make a
    437     * copy of the iov and insert two new vectors at the
    438     * beginning for eth hdr and vlan hdr.  No data is copied,
    439     * just the vectors.
    440     */
    441
    442    of_dpa_flow_pkt_hdr_reset(fc);
    443
    444    fc->iov[2].iov_base = fields->h_proto + 1;
    445    fc->iov[2].iov_len = iov->iov_len - fc->iov[0].iov_len - fc->iov[1].iov_len;
    446
    447    for (i = 1; i < iovcnt; i++) {
    448        fc->iov[i+2] = iov[i];
    449    }
    450
    451    fc->iovcnt = iovcnt + 2;
    452}
    453
    454static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id)
    455{
    456    OfDpaFlowPktFields *fields = &fc->fields;
    457    uint16_t h_proto = fields->ethhdr->h_proto;
    458
    459    if (fields->vlanhdr) {
    460        DPRINTF("flow_pkt_insert_vlan packet already has vlan\n");
    461        return;
    462    }
    463
    464    fields->ethhdr->h_proto = htons(ETH_P_VLAN);
    465    fields->vlanhdr = &fc->vlanhdr;
    466    fields->vlanhdr->h_tci = vlan_id;
    467    fields->vlanhdr->h_proto = h_proto;
    468    fields->h_proto = &fields->vlanhdr->h_proto;
    469
    470    fc->iov[1].iov_base = fields->vlanhdr;
    471    fc->iov[1].iov_len = sizeof(struct vlan_header);
    472}
    473
    474static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc)
    475{
    476    OfDpaFlowPktFields *fields = &fc->fields;
    477
    478    if (!fields->vlanhdr) {
    479        return;
    480    }
    481
    482    fc->iov[0].iov_len -= sizeof(fields->ethhdr->h_proto);
    483    fc->iov[1].iov_base = fields->h_proto;
    484    fc->iov[1].iov_len = sizeof(fields->ethhdr->h_proto);
    485}
    486
    487static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc,
    488                                        uint8_t *src_mac, uint8_t *dst_mac,
    489                                        __be16 vlan_id)
    490{
    491    OfDpaFlowPktFields *fields = &fc->fields;
    492
    493    if (src_mac || dst_mac) {
    494        memcpy(&fc->ethhdr_rewrite, fields->ethhdr, sizeof(struct eth_header));
    495        if (src_mac && memcmp(src_mac, zero_mac.a, ETH_ALEN)) {
    496            memcpy(fc->ethhdr_rewrite.h_source, src_mac, ETH_ALEN);
    497        }
    498        if (dst_mac && memcmp(dst_mac, zero_mac.a, ETH_ALEN)) {
    499            memcpy(fc->ethhdr_rewrite.h_dest, dst_mac, ETH_ALEN);
    500        }
    501        fc->iov[0].iov_base = &fc->ethhdr_rewrite;
    502    }
    503
    504    if (vlan_id && fields->vlanhdr) {
    505        fc->vlanhdr_rewrite = fc->vlanhdr;
    506        fc->vlanhdr_rewrite.h_tci = vlan_id;
    507        fc->iov[1].iov_base = &fc->vlanhdr_rewrite;
    508    }
    509}
    510
    511static void of_dpa_flow_ig_tbl(OfDpaFlowContext *fc, uint32_t tbl_id);
    512
    513static void of_dpa_ig_port_build_match(OfDpaFlowContext *fc,
    514                                       OfDpaFlowMatch *match)
    515{
    516    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
    517    match->value.in_pport = fc->in_pport;
    518    match->value.width = FLOW_KEY_WIDTH(tbl_id);
    519}
    520
    521static void of_dpa_ig_port_miss(OfDpaFlowContext *fc)
    522{
    523    uint32_t port;
    524
    525    /* The default on miss is for packets from physical ports
    526     * to go to the VLAN Flow Table. There is no default rule
    527     * for packets from logical ports, which are dropped on miss.
    528     */
    529
    530    if (fp_port_from_pport(fc->in_pport, &port)) {
    531        of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_VLAN);
    532    }
    533}
    534
    535static void of_dpa_vlan_build_match(OfDpaFlowContext *fc,
    536                                    OfDpaFlowMatch *match)
    537{
    538    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
    539    match->value.in_pport = fc->in_pport;
    540    if (fc->fields.vlanhdr) {
    541        match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
    542    }
    543    match->value.width = FLOW_KEY_WIDTH(eth.vlan_id);
    544}
    545
    546static void of_dpa_vlan_insert(OfDpaFlowContext *fc,
    547                               OfDpaFlow *flow)
    548{
    549    if (flow->action.apply.new_vlan_id) {
    550        of_dpa_flow_pkt_insert_vlan(fc, flow->action.apply.new_vlan_id);
    551    }
    552}
    553
    554static void of_dpa_term_mac_build_match(OfDpaFlowContext *fc,
    555                                        OfDpaFlowMatch *match)
    556{
    557    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
    558    match->value.in_pport = fc->in_pport;
    559    match->value.eth.type = *fc->fields.h_proto;
    560    match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
    561    memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
    562           sizeof(match->value.eth.dst.a));
    563    match->value.width = FLOW_KEY_WIDTH(eth.type);
    564}
    565
    566static void of_dpa_term_mac_miss(OfDpaFlowContext *fc)
    567{
    568    of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_BRIDGING);
    569}
    570
    571static void of_dpa_apply_actions(OfDpaFlowContext *fc,
    572                                 OfDpaFlow *flow)
    573{
    574    fc->action_set.apply.copy_to_cpu = flow->action.apply.copy_to_cpu;
    575    fc->action_set.apply.vlan_id = flow->key.eth.vlan_id;
    576}
    577
    578static void of_dpa_bridging_build_match(OfDpaFlowContext *fc,
    579                                        OfDpaFlowMatch *match)
    580{
    581    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
    582    if (fc->fields.vlanhdr) {
    583        match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
    584    } else if (fc->tunnel_id) {
    585        match->value.tunnel_id = fc->tunnel_id;
    586    }
    587    memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
    588           sizeof(match->value.eth.dst.a));
    589    match->value.width = FLOW_KEY_WIDTH(eth.dst);
    590}
    591
    592static void of_dpa_bridging_learn(OfDpaFlowContext *fc,
    593                                  OfDpaFlow *dst_flow)
    594{
    595    OfDpaFlowMatch match = { { 0, }, };
    596    OfDpaFlow *flow;
    597    uint8_t *addr;
    598    uint16_t vlan_id;
    599    int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
    600    int64_t refresh_delay = 1;
    601
    602    /* Do a lookup in bridge table by src_mac/vlan */
    603
    604    addr = fc->fields.ethhdr->h_source;
    605    vlan_id = fc->fields.vlanhdr->h_tci;
    606
    607    match.value.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
    608    match.value.eth.vlan_id = vlan_id;
    609    memcpy(match.value.eth.dst.a, addr, sizeof(match.value.eth.dst.a));
    610    match.value.width = FLOW_KEY_WIDTH(eth.dst);
    611
    612    flow = of_dpa_flow_match(fc->of_dpa, &match);
    613    if (flow) {
    614        if (!memcmp(flow->mask.eth.dst.a, ff_mac.a,
    615                    sizeof(flow->mask.eth.dst.a))) {
    616            /* src_mac/vlan already learned; if in_port and out_port
    617             * don't match, the end station has moved and the port
    618             * needs updating */
    619            /* XXX implement the in_port/out_port check */
    620            if (now - flow->stats.refresh_time < refresh_delay) {
    621                return;
    622            }
    623            flow->stats.refresh_time = now;
    624        }
    625    }
    626
    627    /* Let driver know about mac/vlan.  This may be a new mac/vlan
    628     * or a refresh of existing mac/vlan that's been hit after the
    629     * refresh_delay.
    630     */
    631
    632    rocker_event_mac_vlan_seen(world_rocker(fc->of_dpa->world),
    633                               fc->in_pport, addr, vlan_id);
    634}
    635
    636static void of_dpa_bridging_miss(OfDpaFlowContext *fc)
    637{
    638    of_dpa_bridging_learn(fc, NULL);
    639    of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY);
    640}
    641
    642static void of_dpa_bridging_action_write(OfDpaFlowContext *fc,
    643                                         OfDpaFlow *flow)
    644{
    645    if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
    646        fc->action_set.write.group_id = flow->action.write.group_id;
    647    }
    648    fc->action_set.write.tun_log_lport = flow->action.write.tun_log_lport;
    649}
    650
    651static void of_dpa_unicast_routing_build_match(OfDpaFlowContext *fc,
    652                                               OfDpaFlowMatch *match)
    653{
    654    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
    655    match->value.eth.type = *fc->fields.h_proto;
    656    if (fc->fields.ipv4hdr) {
    657        match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst;
    658    }
    659    if (fc->fields.ipv6_dst_addr) {
    660        memcpy(&match->value.ipv6.addr.dst, fc->fields.ipv6_dst_addr,
    661               sizeof(match->value.ipv6.addr.dst));
    662    }
    663    match->value.width = FLOW_KEY_WIDTH(ipv6.addr.dst);
    664}
    665
    666static void of_dpa_unicast_routing_miss(OfDpaFlowContext *fc)
    667{
    668    of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY);
    669}
    670
    671static void of_dpa_unicast_routing_action_write(OfDpaFlowContext *fc,
    672                                                OfDpaFlow *flow)
    673{
    674    if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
    675        fc->action_set.write.group_id = flow->action.write.group_id;
    676    }
    677}
    678
    679static void
    680of_dpa_multicast_routing_build_match(OfDpaFlowContext *fc,
    681                                     OfDpaFlowMatch *match)
    682{
    683    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
    684    match->value.eth.type = *fc->fields.h_proto;
    685    match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
    686    if (fc->fields.ipv4hdr) {
    687        match->value.ipv4.addr.src = fc->fields.ipv4hdr->ip_src;
    688        match->value.ipv4.addr.dst = fc->fields.ipv4hdr->ip_dst;
    689    }
    690    if (fc->fields.ipv6_src_addr) {
    691        memcpy(&match->value.ipv6.addr.src, fc->fields.ipv6_src_addr,
    692               sizeof(match->value.ipv6.addr.src));
    693    }
    694    if (fc->fields.ipv6_dst_addr) {
    695        memcpy(&match->value.ipv6.addr.dst, fc->fields.ipv6_dst_addr,
    696               sizeof(match->value.ipv6.addr.dst));
    697    }
    698    match->value.width = FLOW_KEY_WIDTH(ipv6.addr.dst);
    699}
    700
    701static void of_dpa_multicast_routing_miss(OfDpaFlowContext *fc)
    702{
    703    of_dpa_flow_ig_tbl(fc, ROCKER_OF_DPA_TABLE_ID_ACL_POLICY);
    704}
    705
    706static void
    707of_dpa_multicast_routing_action_write(OfDpaFlowContext *fc,
    708                                      OfDpaFlow *flow)
    709{
    710    if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
    711        fc->action_set.write.group_id = flow->action.write.group_id;
    712    }
    713    fc->action_set.write.vlan_id = flow->action.write.vlan_id;
    714}
    715
    716static void of_dpa_acl_build_match(OfDpaFlowContext *fc,
    717                                   OfDpaFlowMatch *match)
    718{
    719    match->value.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
    720    match->value.in_pport = fc->in_pport;
    721    memcpy(match->value.eth.src.a, fc->fields.ethhdr->h_source,
    722           sizeof(match->value.eth.src.a));
    723    memcpy(match->value.eth.dst.a, fc->fields.ethhdr->h_dest,
    724           sizeof(match->value.eth.dst.a));
    725    match->value.eth.type = *fc->fields.h_proto;
    726    match->value.eth.vlan_id = fc->fields.vlanhdr->h_tci;
    727    match->value.width = FLOW_KEY_WIDTH(eth.type);
    728    if (fc->fields.ipv4hdr) {
    729        match->value.ip.proto = fc->fields.ipv4hdr->ip_p;
    730        match->value.ip.tos = fc->fields.ipv4hdr->ip_tos;
    731        match->value.width = FLOW_KEY_WIDTH(ip.tos);
    732    } else if (fc->fields.ipv6hdr) {
    733        match->value.ip.proto =
    734            fc->fields.ipv6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt;
    735        match->value.ip.tos = 0; /* XXX what goes here? */
    736        match->value.width = FLOW_KEY_WIDTH(ip.tos);
    737    }
    738}
    739
    740static void of_dpa_eg(OfDpaFlowContext *fc);
    741static void of_dpa_acl_hit(OfDpaFlowContext *fc,
    742                           OfDpaFlow *dst_flow)
    743{
    744    of_dpa_eg(fc);
    745}
    746
    747static void of_dpa_acl_action_write(OfDpaFlowContext *fc,
    748                                    OfDpaFlow *flow)
    749{
    750    if (flow->action.write.group_id != ROCKER_GROUP_NONE) {
    751        fc->action_set.write.group_id = flow->action.write.group_id;
    752    }
    753}
    754
    755static void of_dpa_drop(OfDpaFlowContext *fc)
    756{
    757    /* drop packet */
    758}
    759
    760static OfDpaGroup *of_dpa_group_find(OfDpa *of_dpa,
    761                                              uint32_t group_id)
    762{
    763    return g_hash_table_lookup(of_dpa->group_tbl, &group_id);
    764}
    765
    766static int of_dpa_group_add(OfDpa *of_dpa, OfDpaGroup *group)
    767{
    768    g_hash_table_insert(of_dpa->group_tbl, &group->id, group);
    769
    770    return 0;
    771}
    772
    773#if 0
    774static int of_dpa_group_mod(OfDpa *of_dpa, OfDpaGroup *group)
    775{
    776    OfDpaGroup *old_group = of_dpa_group_find(of_dpa, group->id);
    777
    778    if (!old_group) {
    779        return -ENOENT;
    780    }
    781
    782    /* XXX */
    783
    784    return 0;
    785}
    786#endif
    787
    788static int of_dpa_group_del(OfDpa *of_dpa, OfDpaGroup *group)
    789{
    790    g_hash_table_remove(of_dpa->group_tbl, &group->id);
    791
    792    return 0;
    793}
    794
    795#if 0
    796static int of_dpa_group_get_stats(OfDpa *of_dpa, uint32_t id)
    797{
    798    OfDpaGroup *group = of_dpa_group_find(of_dpa, id);
    799
    800    if (!group) {
    801        return -ENOENT;
    802    }
    803
    804    /* XXX get/return stats */
    805
    806    return 0;
    807}
    808#endif
    809
    810static OfDpaGroup *of_dpa_group_alloc(uint32_t id)
    811{
    812    OfDpaGroup *group = g_new0(OfDpaGroup, 1);
    813
    814    group->id = id;
    815
    816    return group;
    817}
    818
    819static void of_dpa_output_l2_interface(OfDpaFlowContext *fc,
    820                                       OfDpaGroup *group)
    821{
    822    uint8_t copy_to_cpu = fc->action_set.apply.copy_to_cpu;
    823
    824    if (group->l2_interface.pop_vlan) {
    825        of_dpa_flow_pkt_strip_vlan(fc);
    826    }
    827
    828    /* Note: By default, and as per the OpenFlow 1.3.1
    829     * specification, a packet cannot be forwarded back
    830     * to the IN_PORT from which it came in. An action
    831     * bucket that specifies the particular packet's
    832     * egress port is not evaluated.
    833     */
    834
    835    if (group->l2_interface.out_pport == 0) {
    836        rx_produce(fc->of_dpa->world, fc->in_pport, fc->iov, fc->iovcnt,
    837                   copy_to_cpu);
    838    } else if (group->l2_interface.out_pport != fc->in_pport) {
    839        rocker_port_eg(world_rocker(fc->of_dpa->world),
    840                       group->l2_interface.out_pport,
    841                       fc->iov, fc->iovcnt);
    842    }
    843}
    844
    845static void of_dpa_output_l2_rewrite(OfDpaFlowContext *fc,
    846                                     OfDpaGroup *group)
    847{
    848    OfDpaGroup *l2_group =
    849        of_dpa_group_find(fc->of_dpa, group->l2_rewrite.group_id);
    850
    851    if (!l2_group) {
    852        return;
    853    }
    854
    855    of_dpa_flow_pkt_hdr_rewrite(fc, group->l2_rewrite.src_mac.a,
    856                         group->l2_rewrite.dst_mac.a,
    857                         group->l2_rewrite.vlan_id);
    858    of_dpa_output_l2_interface(fc, l2_group);
    859}
    860
    861static void of_dpa_output_l2_flood(OfDpaFlowContext *fc,
    862                                   OfDpaGroup *group)
    863{
    864    OfDpaGroup *l2_group;
    865    int i;
    866
    867    for (i = 0; i < group->l2_flood.group_count; i++) {
    868        of_dpa_flow_pkt_hdr_reset(fc);
    869        l2_group = of_dpa_group_find(fc->of_dpa, group->l2_flood.group_ids[i]);
    870        if (!l2_group) {
    871            continue;
    872        }
    873        switch (ROCKER_GROUP_TYPE_GET(l2_group->id)) {
    874        case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
    875            of_dpa_output_l2_interface(fc, l2_group);
    876            break;
    877        case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
    878            of_dpa_output_l2_rewrite(fc, l2_group);
    879            break;
    880        }
    881    }
    882}
    883
    884static void of_dpa_output_l3_unicast(OfDpaFlowContext *fc, OfDpaGroup *group)
    885{
    886    OfDpaGroup *l2_group =
    887        of_dpa_group_find(fc->of_dpa, group->l3_unicast.group_id);
    888
    889    if (!l2_group) {
    890        return;
    891    }
    892
    893    of_dpa_flow_pkt_hdr_rewrite(fc, group->l3_unicast.src_mac.a,
    894                                group->l3_unicast.dst_mac.a,
    895                                group->l3_unicast.vlan_id);
    896    /* XXX need ttl_check */
    897    of_dpa_output_l2_interface(fc, l2_group);
    898}
    899
    900static void of_dpa_eg(OfDpaFlowContext *fc)
    901{
    902    OfDpaFlowAction *set = &fc->action_set;
    903    OfDpaGroup *group;
    904    uint32_t group_id;
    905
    906    /* send a copy of pkt to CPU (controller)? */
    907
    908    if (set->apply.copy_to_cpu) {
    909        group_id = ROCKER_GROUP_L2_INTERFACE(set->apply.vlan_id, 0);
    910        group = of_dpa_group_find(fc->of_dpa, group_id);
    911        if (group) {
    912            of_dpa_output_l2_interface(fc, group);
    913            of_dpa_flow_pkt_hdr_reset(fc);
    914        }
    915    }
    916
    917    /* process group write actions */
    918
    919    if (!set->write.group_id) {
    920        return;
    921    }
    922
    923    group = of_dpa_group_find(fc->of_dpa, set->write.group_id);
    924    if (!group) {
    925        return;
    926    }
    927
    928    switch (ROCKER_GROUP_TYPE_GET(group->id)) {
    929    case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
    930        of_dpa_output_l2_interface(fc, group);
    931        break;
    932    case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
    933        of_dpa_output_l2_rewrite(fc, group);
    934        break;
    935    case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
    936    case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
    937        of_dpa_output_l2_flood(fc, group);
    938        break;
    939    case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
    940        of_dpa_output_l3_unicast(fc, group);
    941        break;
    942    }
    943}
    944
    945typedef struct of_dpa_flow_tbl_ops {
    946    void (*build_match)(OfDpaFlowContext *fc, OfDpaFlowMatch *match);
    947    void (*hit)(OfDpaFlowContext *fc, OfDpaFlow *flow);
    948    void (*miss)(OfDpaFlowContext *fc);
    949    void (*hit_no_goto)(OfDpaFlowContext *fc);
    950    void (*action_apply)(OfDpaFlowContext *fc, OfDpaFlow *flow);
    951    void (*action_write)(OfDpaFlowContext *fc, OfDpaFlow *flow);
    952} OfDpaFlowTblOps;
    953
    954static OfDpaFlowTblOps of_dpa_tbl_ops[] = {
    955    [ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT] = {
    956        .build_match = of_dpa_ig_port_build_match,
    957        .miss = of_dpa_ig_port_miss,
    958        .hit_no_goto = of_dpa_drop,
    959    },
    960    [ROCKER_OF_DPA_TABLE_ID_VLAN] = {
    961        .build_match = of_dpa_vlan_build_match,
    962        .hit_no_goto = of_dpa_drop,
    963        .action_apply = of_dpa_vlan_insert,
    964    },
    965    [ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC] = {
    966        .build_match = of_dpa_term_mac_build_match,
    967        .miss = of_dpa_term_mac_miss,
    968        .hit_no_goto = of_dpa_drop,
    969        .action_apply = of_dpa_apply_actions,
    970    },
    971    [ROCKER_OF_DPA_TABLE_ID_BRIDGING] = {
    972        .build_match = of_dpa_bridging_build_match,
    973        .hit = of_dpa_bridging_learn,
    974        .miss = of_dpa_bridging_miss,
    975        .hit_no_goto = of_dpa_drop,
    976        .action_apply = of_dpa_apply_actions,
    977        .action_write = of_dpa_bridging_action_write,
    978    },
    979    [ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING] = {
    980        .build_match = of_dpa_unicast_routing_build_match,
    981        .miss = of_dpa_unicast_routing_miss,
    982        .hit_no_goto = of_dpa_drop,
    983        .action_write = of_dpa_unicast_routing_action_write,
    984    },
    985    [ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING] = {
    986        .build_match = of_dpa_multicast_routing_build_match,
    987        .miss = of_dpa_multicast_routing_miss,
    988        .hit_no_goto = of_dpa_drop,
    989        .action_write = of_dpa_multicast_routing_action_write,
    990    },
    991    [ROCKER_OF_DPA_TABLE_ID_ACL_POLICY] = {
    992        .build_match = of_dpa_acl_build_match,
    993        .hit = of_dpa_acl_hit,
    994        .miss = of_dpa_eg,
    995        .action_apply = of_dpa_apply_actions,
    996        .action_write = of_dpa_acl_action_write,
    997    },
    998};
    999
   1000static void of_dpa_flow_ig_tbl(OfDpaFlowContext *fc, uint32_t tbl_id)
   1001{
   1002    OfDpaFlowTblOps *ops = &of_dpa_tbl_ops[tbl_id];
   1003    OfDpaFlowMatch match = { { 0, }, };
   1004    OfDpaFlow *flow;
   1005
   1006    if (ops->build_match) {
   1007        ops->build_match(fc, &match);
   1008    } else {
   1009        return;
   1010    }
   1011
   1012    flow = of_dpa_flow_match(fc->of_dpa, &match);
   1013    if (!flow) {
   1014        if (ops->miss) {
   1015            ops->miss(fc);
   1016        }
   1017        return;
   1018    }
   1019
   1020    flow->stats.hits++;
   1021
   1022    if (ops->action_apply) {
   1023        ops->action_apply(fc, flow);
   1024    }
   1025
   1026    if (ops->action_write) {
   1027        ops->action_write(fc, flow);
   1028    }
   1029
   1030    if (ops->hit) {
   1031        ops->hit(fc, flow);
   1032    }
   1033
   1034    if (flow->action.goto_tbl) {
   1035        of_dpa_flow_ig_tbl(fc, flow->action.goto_tbl);
   1036    } else if (ops->hit_no_goto) {
   1037        ops->hit_no_goto(fc);
   1038    }
   1039
   1040    /* drop packet */
   1041}
   1042
   1043static ssize_t of_dpa_ig(World *world, uint32_t pport,
   1044                         const struct iovec *iov, int iovcnt)
   1045{
   1046    struct iovec iov_copy[iovcnt + 2];
   1047    OfDpaFlowContext fc = {
   1048        .of_dpa = world_private(world),
   1049        .in_pport = pport,
   1050        .iov = iov_copy,
   1051        .iovcnt = iovcnt + 2,
   1052    };
   1053
   1054    of_dpa_flow_pkt_parse(&fc, iov, iovcnt);
   1055    of_dpa_flow_ig_tbl(&fc, ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT);
   1056
   1057    return iov_size(iov, iovcnt);
   1058}
   1059
   1060#define ROCKER_TUNNEL_LPORT 0x00010000
   1061
   1062static int of_dpa_cmd_add_ig_port(OfDpaFlow *flow, RockerTlv **flow_tlvs)
   1063{
   1064    OfDpaFlowKey *key = &flow->key;
   1065    OfDpaFlowKey *mask = &flow->mask;
   1066    OfDpaFlowAction *action = &flow->action;
   1067    bool overlay_tunnel;
   1068
   1069    if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
   1070        !flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
   1071        return -ROCKER_EINVAL;
   1072    }
   1073
   1074    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
   1075    key->width = FLOW_KEY_WIDTH(tbl_id);
   1076
   1077    key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
   1078    if (flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]) {
   1079        mask->in_pport =
   1080            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]);
   1081    }
   1082
   1083    overlay_tunnel = !!(key->in_pport & ROCKER_TUNNEL_LPORT);
   1084
   1085    action->goto_tbl =
   1086        rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
   1087
   1088    if (!overlay_tunnel && action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_VLAN) {
   1089        return -ROCKER_EINVAL;
   1090    }
   1091
   1092    if (overlay_tunnel && action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_BRIDGING) {
   1093        return -ROCKER_EINVAL;
   1094    }
   1095
   1096    return ROCKER_OK;
   1097}
   1098
   1099static int of_dpa_cmd_add_vlan(OfDpaFlow *flow, RockerTlv **flow_tlvs)
   1100{
   1101    OfDpaFlowKey *key = &flow->key;
   1102    OfDpaFlowKey *mask = &flow->mask;
   1103    OfDpaFlowAction *action = &flow->action;
   1104    uint32_t port;
   1105    bool untagged;
   1106
   1107    if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
   1108        !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
   1109        DPRINTF("Must give in_pport and vlan_id to install VLAN tbl entry\n");
   1110        return -ROCKER_EINVAL;
   1111    }
   1112
   1113    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
   1114    key->width = FLOW_KEY_WIDTH(eth.vlan_id);
   1115
   1116    key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
   1117    if (!fp_port_from_pport(key->in_pport, &port)) {
   1118        DPRINTF("in_pport (%d) not a front-panel port\n", key->in_pport);
   1119        return -ROCKER_EINVAL;
   1120    }
   1121    mask->in_pport = 0xffffffff;
   1122
   1123    key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   1124
   1125    if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) {
   1126        mask->eth.vlan_id =
   1127            rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]);
   1128    }
   1129
   1130    if (key->eth.vlan_id) {
   1131        untagged = false; /* filtering */
   1132    } else {
   1133        untagged = true;
   1134    }
   1135
   1136    if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
   1137        action->goto_tbl =
   1138            rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
   1139        if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC) {
   1140            DPRINTF("Goto tbl (%d) must be TERM_MAC\n", action->goto_tbl);
   1141            return -ROCKER_EINVAL;
   1142        }
   1143    }
   1144
   1145    if (untagged) {
   1146        if (!flow_tlvs[ROCKER_TLV_OF_DPA_NEW_VLAN_ID]) {
   1147            DPRINTF("Must specify new vlan_id if untagged\n");
   1148            return -ROCKER_EINVAL;
   1149        }
   1150        action->apply.new_vlan_id =
   1151            rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_NEW_VLAN_ID]);
   1152        if (1 > ntohs(action->apply.new_vlan_id) ||
   1153            ntohs(action->apply.new_vlan_id) > 4095) {
   1154            DPRINTF("New vlan_id (%d) must be between 1 and 4095\n",
   1155                    ntohs(action->apply.new_vlan_id));
   1156            return -ROCKER_EINVAL;
   1157        }
   1158    }
   1159
   1160    return ROCKER_OK;
   1161}
   1162
   1163static int of_dpa_cmd_add_term_mac(OfDpaFlow *flow, RockerTlv **flow_tlvs)
   1164{
   1165    OfDpaFlowKey *key = &flow->key;
   1166    OfDpaFlowKey *mask = &flow->mask;
   1167    OfDpaFlowAction *action = &flow->action;
   1168    const MACAddr ipv4_mcast = { .a = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 } };
   1169    const MACAddr ipv4_mask =  { .a = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 } };
   1170    const MACAddr ipv6_mcast = { .a = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 } };
   1171    const MACAddr ipv6_mask =  { .a = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } };
   1172    uint32_t port;
   1173    bool unicast = false;
   1174    bool multicast = false;
   1175
   1176    if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
   1177        !flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK] ||
   1178        !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE] ||
   1179        !flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC] ||
   1180        !flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK] ||
   1181        !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID] ||
   1182        !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) {
   1183        return -ROCKER_EINVAL;
   1184    }
   1185
   1186    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
   1187    key->width = FLOW_KEY_WIDTH(eth.type);
   1188
   1189    key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
   1190    if (!fp_port_from_pport(key->in_pport, &port)) {
   1191        return -ROCKER_EINVAL;
   1192    }
   1193    mask->in_pport =
   1194        rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]);
   1195
   1196    key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
   1197    if (key->eth.type != htons(0x0800) && key->eth.type != htons(0x86dd)) {
   1198        return -ROCKER_EINVAL;
   1199    }
   1200    mask->eth.type = htons(0xffff);
   1201
   1202    memcpy(key->eth.dst.a,
   1203           rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
   1204           sizeof(key->eth.dst.a));
   1205    memcpy(mask->eth.dst.a,
   1206           rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]),
   1207           sizeof(mask->eth.dst.a));
   1208
   1209    if ((key->eth.dst.a[0] & 0x01) == 0x00) {
   1210        unicast = true;
   1211    }
   1212
   1213    /* only two wildcard rules are acceptable for IPv4 and IPv6 multicast */
   1214    if (memcmp(key->eth.dst.a, ipv4_mcast.a, sizeof(key->eth.dst.a)) == 0 &&
   1215        memcmp(mask->eth.dst.a, ipv4_mask.a, sizeof(mask->eth.dst.a)) == 0) {
   1216        multicast = true;
   1217    }
   1218    if (memcmp(key->eth.dst.a, ipv6_mcast.a, sizeof(key->eth.dst.a)) == 0 &&
   1219        memcmp(mask->eth.dst.a, ipv6_mask.a, sizeof(mask->eth.dst.a)) == 0) {
   1220        multicast = true;
   1221    }
   1222
   1223    if (!unicast && !multicast) {
   1224        return -ROCKER_EINVAL;
   1225    }
   1226
   1227    key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   1228    mask->eth.vlan_id =
   1229        rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]);
   1230
   1231    if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
   1232        action->goto_tbl =
   1233            rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
   1234
   1235        if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING &&
   1236            action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING) {
   1237            return -ROCKER_EINVAL;
   1238        }
   1239
   1240        if (unicast &&
   1241            action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING) {
   1242            return -ROCKER_EINVAL;
   1243        }
   1244
   1245        if (multicast &&
   1246            action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING) {
   1247            return -ROCKER_EINVAL;
   1248        }
   1249    }
   1250
   1251    if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) {
   1252        action->apply.copy_to_cpu =
   1253            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]);
   1254    }
   1255
   1256    return ROCKER_OK;
   1257}
   1258
   1259static int of_dpa_cmd_add_bridging(OfDpaFlow *flow, RockerTlv **flow_tlvs)
   1260{
   1261    OfDpaFlowKey *key = &flow->key;
   1262    OfDpaFlowKey *mask = &flow->mask;
   1263    OfDpaFlowAction *action = &flow->action;
   1264    bool unicast = false;
   1265    bool dst_mac = false;
   1266    bool dst_mac_mask = false;
   1267    enum {
   1268        BRIDGING_MODE_UNKNOWN,
   1269        BRIDGING_MODE_VLAN_UCAST,
   1270        BRIDGING_MODE_VLAN_MCAST,
   1271        BRIDGING_MODE_VLAN_DFLT,
   1272        BRIDGING_MODE_TUNNEL_UCAST,
   1273        BRIDGING_MODE_TUNNEL_MCAST,
   1274        BRIDGING_MODE_TUNNEL_DFLT,
   1275    } mode = BRIDGING_MODE_UNKNOWN;
   1276
   1277    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
   1278
   1279    if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
   1280        key->eth.vlan_id =
   1281            rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   1282        mask->eth.vlan_id = 0xffff;
   1283        key->width = FLOW_KEY_WIDTH(eth.vlan_id);
   1284    }
   1285
   1286    if (flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]) {
   1287        key->tunnel_id =
   1288            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]);
   1289        mask->tunnel_id = 0xffffffff;
   1290        key->width = FLOW_KEY_WIDTH(tunnel_id);
   1291    }
   1292
   1293    /* can't do VLAN bridging and tunnel bridging at same time */
   1294    if (key->eth.vlan_id && key->tunnel_id) {
   1295        DPRINTF("can't do VLAN bridging and tunnel bridging at same time\n");
   1296        return -ROCKER_EINVAL;
   1297    }
   1298
   1299    if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
   1300        memcpy(key->eth.dst.a,
   1301               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
   1302               sizeof(key->eth.dst.a));
   1303        key->width = FLOW_KEY_WIDTH(eth.dst);
   1304        dst_mac = true;
   1305        unicast = (key->eth.dst.a[0] & 0x01) == 0x00;
   1306    }
   1307
   1308    if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]) {
   1309        memcpy(mask->eth.dst.a,
   1310               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]),
   1311               sizeof(mask->eth.dst.a));
   1312        key->width = FLOW_KEY_WIDTH(eth.dst);
   1313        dst_mac_mask = true;
   1314    } else if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
   1315        memcpy(mask->eth.dst.a, ff_mac.a, sizeof(mask->eth.dst.a));
   1316    }
   1317
   1318    if (key->eth.vlan_id) {
   1319        if (dst_mac && !dst_mac_mask) {
   1320            mode = unicast ? BRIDGING_MODE_VLAN_UCAST :
   1321                             BRIDGING_MODE_VLAN_MCAST;
   1322        } else if ((dst_mac && dst_mac_mask) || !dst_mac) {
   1323            mode = BRIDGING_MODE_VLAN_DFLT;
   1324        }
   1325    } else if (key->tunnel_id) {
   1326        if (dst_mac && !dst_mac_mask) {
   1327            mode = unicast ? BRIDGING_MODE_TUNNEL_UCAST :
   1328                             BRIDGING_MODE_TUNNEL_MCAST;
   1329        } else if ((dst_mac && dst_mac_mask) || !dst_mac) {
   1330            mode = BRIDGING_MODE_TUNNEL_DFLT;
   1331        }
   1332    }
   1333
   1334    if (mode == BRIDGING_MODE_UNKNOWN) {
   1335        DPRINTF("Unknown bridging mode\n");
   1336        return -ROCKER_EINVAL;
   1337    }
   1338
   1339    if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
   1340        action->goto_tbl =
   1341            rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
   1342        if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) {
   1343            DPRINTF("Briding goto tbl must be ACL policy\n");
   1344            return -ROCKER_EINVAL;
   1345        }
   1346    }
   1347
   1348    if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
   1349        action->write.group_id =
   1350            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
   1351        switch (mode) {
   1352        case BRIDGING_MODE_VLAN_UCAST:
   1353            if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
   1354                ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) {
   1355                DPRINTF("Bridging mode vlan ucast needs L2 "
   1356                        "interface group (0x%08x)\n",
   1357                        action->write.group_id);
   1358                return -ROCKER_EINVAL;
   1359            }
   1360            break;
   1361        case BRIDGING_MODE_VLAN_MCAST:
   1362            if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
   1363                ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) {
   1364                DPRINTF("Bridging mode vlan mcast needs L2 "
   1365                        "mcast group (0x%08x)\n",
   1366                        action->write.group_id);
   1367                return -ROCKER_EINVAL;
   1368            }
   1369            break;
   1370        case BRIDGING_MODE_VLAN_DFLT:
   1371            if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
   1372                ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) {
   1373                DPRINTF("Bridging mode vlan dflt needs L2 "
   1374                        "flood group (0x%08x)\n",
   1375                        action->write.group_id);
   1376                return -ROCKER_EINVAL;
   1377            }
   1378            break;
   1379        case BRIDGING_MODE_TUNNEL_MCAST:
   1380            if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
   1381                ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY) {
   1382                DPRINTF("Bridging mode tunnel mcast needs L2 "
   1383                        "overlay group (0x%08x)\n",
   1384                        action->write.group_id);
   1385                return -ROCKER_EINVAL;
   1386            }
   1387            break;
   1388        case BRIDGING_MODE_TUNNEL_DFLT:
   1389            if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
   1390                ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY) {
   1391                DPRINTF("Bridging mode tunnel dflt needs L2 "
   1392                        "overlay group (0x%08x)\n",
   1393                        action->write.group_id);
   1394                return -ROCKER_EINVAL;
   1395            }
   1396            break;
   1397        default:
   1398            return -ROCKER_EINVAL;
   1399        }
   1400    }
   1401
   1402    if (flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_LPORT]) {
   1403        action->write.tun_log_lport =
   1404            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_LPORT]);
   1405        if (mode != BRIDGING_MODE_TUNNEL_UCAST) {
   1406            DPRINTF("Have tunnel logical port but not "
   1407                    "in bridging tunnel mode\n");
   1408            return -ROCKER_EINVAL;
   1409        }
   1410    }
   1411
   1412    if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) {
   1413        action->apply.copy_to_cpu =
   1414            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]);
   1415    }
   1416
   1417    return ROCKER_OK;
   1418}
   1419
   1420static int of_dpa_cmd_add_unicast_routing(OfDpaFlow *flow,
   1421                                          RockerTlv **flow_tlvs)
   1422{
   1423    OfDpaFlowKey *key = &flow->key;
   1424    OfDpaFlowKey *mask = &flow->mask;
   1425    OfDpaFlowAction *action = &flow->action;
   1426    enum {
   1427        UNICAST_ROUTING_MODE_UNKNOWN,
   1428        UNICAST_ROUTING_MODE_IPV4,
   1429        UNICAST_ROUTING_MODE_IPV6,
   1430    } mode = UNICAST_ROUTING_MODE_UNKNOWN;
   1431    uint8_t type;
   1432
   1433    if (!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) {
   1434        return -ROCKER_EINVAL;
   1435    }
   1436
   1437    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
   1438    key->width = FLOW_KEY_WIDTH(ipv6.addr.dst);
   1439
   1440    key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
   1441    switch (ntohs(key->eth.type)) {
   1442    case 0x0800:
   1443        mode = UNICAST_ROUTING_MODE_IPV4;
   1444        break;
   1445    case 0x86dd:
   1446        mode = UNICAST_ROUTING_MODE_IPV6;
   1447        break;
   1448    default:
   1449        return -ROCKER_EINVAL;
   1450    }
   1451    mask->eth.type = htons(0xffff);
   1452
   1453    switch (mode) {
   1454    case UNICAST_ROUTING_MODE_IPV4:
   1455        if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]) {
   1456            return -ROCKER_EINVAL;
   1457        }
   1458        key->ipv4.addr.dst =
   1459            rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]);
   1460        if (ipv4_addr_is_multicast(key->ipv4.addr.dst)) {
   1461            return -ROCKER_EINVAL;
   1462        }
   1463        flow->lpm = of_dpa_mask2prefix(htonl(0xffffffff));
   1464        if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP_MASK]) {
   1465            mask->ipv4.addr.dst =
   1466                rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP_MASK]);
   1467            flow->lpm = of_dpa_mask2prefix(mask->ipv4.addr.dst);
   1468        }
   1469        break;
   1470    case UNICAST_ROUTING_MODE_IPV6:
   1471        if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]) {
   1472            return -ROCKER_EINVAL;
   1473        }
   1474        memcpy(&key->ipv6.addr.dst,
   1475               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]),
   1476               sizeof(key->ipv6.addr.dst));
   1477        if (ipv6_addr_is_multicast(&key->ipv6.addr.dst)) {
   1478            return -ROCKER_EINVAL;
   1479        }
   1480        if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6_MASK]) {
   1481            memcpy(&mask->ipv6.addr.dst,
   1482                   rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6_MASK]),
   1483                   sizeof(mask->ipv6.addr.dst));
   1484        }
   1485        break;
   1486    default:
   1487        return -ROCKER_EINVAL;
   1488    }
   1489
   1490    if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
   1491        action->goto_tbl =
   1492            rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
   1493        if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) {
   1494            return -ROCKER_EINVAL;
   1495        }
   1496    }
   1497
   1498    if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
   1499        action->write.group_id =
   1500            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
   1501        type = ROCKER_GROUP_TYPE_GET(action->write.group_id);
   1502        if (type != ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE &&
   1503            type != ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST &&
   1504            type != ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP) {
   1505            return -ROCKER_EINVAL;
   1506        }
   1507    }
   1508
   1509    return ROCKER_OK;
   1510}
   1511
   1512static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow,
   1513                                            RockerTlv **flow_tlvs)
   1514{
   1515    OfDpaFlowKey *key = &flow->key;
   1516    OfDpaFlowKey *mask = &flow->mask;
   1517    OfDpaFlowAction *action = &flow->action;
   1518    enum {
   1519        MULTICAST_ROUTING_MODE_UNKNOWN,
   1520        MULTICAST_ROUTING_MODE_IPV4,
   1521        MULTICAST_ROUTING_MODE_IPV6,
   1522    } mode = MULTICAST_ROUTING_MODE_UNKNOWN;
   1523
   1524    if (!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE] ||
   1525        !flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
   1526        return -ROCKER_EINVAL;
   1527    }
   1528
   1529    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
   1530    key->width = FLOW_KEY_WIDTH(ipv6.addr.dst);
   1531
   1532    key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
   1533    switch (ntohs(key->eth.type)) {
   1534    case 0x0800:
   1535        mode = MULTICAST_ROUTING_MODE_IPV4;
   1536        break;
   1537    case 0x86dd:
   1538        mode = MULTICAST_ROUTING_MODE_IPV6;
   1539        break;
   1540    default:
   1541        return -ROCKER_EINVAL;
   1542    }
   1543
   1544    key->eth.vlan_id = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   1545
   1546    switch (mode) {
   1547    case MULTICAST_ROUTING_MODE_IPV4:
   1548
   1549        if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]) {
   1550            key->ipv4.addr.src =
   1551                rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]);
   1552        }
   1553
   1554        if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP_MASK]) {
   1555            mask->ipv4.addr.src =
   1556                rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP_MASK]);
   1557        }
   1558
   1559        if (!flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IP]) {
   1560            if (mask->ipv4.addr.src != 0) {
   1561                return -ROCKER_EINVAL;
   1562            }
   1563        }
   1564
   1565        if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]) {
   1566            return -ROCKER_EINVAL;
   1567        }
   1568
   1569        key->ipv4.addr.dst =
   1570            rocker_tlv_get_u32(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IP]);
   1571        if (!ipv4_addr_is_multicast(key->ipv4.addr.dst)) {
   1572            return -ROCKER_EINVAL;
   1573        }
   1574
   1575        break;
   1576
   1577    case MULTICAST_ROUTING_MODE_IPV6:
   1578
   1579        if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]) {
   1580            memcpy(&key->ipv6.addr.src,
   1581                   rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]),
   1582                   sizeof(key->ipv6.addr.src));
   1583        }
   1584
   1585        if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6_MASK]) {
   1586            memcpy(&mask->ipv6.addr.src,
   1587                   rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6_MASK]),
   1588                   sizeof(mask->ipv6.addr.src));
   1589        }
   1590
   1591        if (!flow_tlvs[ROCKER_TLV_OF_DPA_SRC_IPV6]) {
   1592            if (mask->ipv6.addr.src.addr32[0] != 0 &&
   1593                mask->ipv6.addr.src.addr32[1] != 0 &&
   1594                mask->ipv6.addr.src.addr32[2] != 0 &&
   1595                mask->ipv6.addr.src.addr32[3] != 0) {
   1596                return -ROCKER_EINVAL;
   1597            }
   1598        }
   1599
   1600        if (!flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]) {
   1601            return -ROCKER_EINVAL;
   1602        }
   1603
   1604        memcpy(&key->ipv6.addr.dst,
   1605               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_IPV6]),
   1606               sizeof(key->ipv6.addr.dst));
   1607        if (!ipv6_addr_is_multicast(&key->ipv6.addr.dst)) {
   1608            return -ROCKER_EINVAL;
   1609        }
   1610
   1611        break;
   1612
   1613    default:
   1614        return -ROCKER_EINVAL;
   1615    }
   1616
   1617    if (flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]) {
   1618        action->goto_tbl =
   1619            rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_GOTO_TABLE_ID]);
   1620        if (action->goto_tbl != ROCKER_OF_DPA_TABLE_ID_ACL_POLICY) {
   1621            return -ROCKER_EINVAL;
   1622        }
   1623    }
   1624
   1625    if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
   1626        action->write.group_id =
   1627            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
   1628        if (ROCKER_GROUP_TYPE_GET(action->write.group_id) !=
   1629            ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST) {
   1630            return -ROCKER_EINVAL;
   1631        }
   1632        action->write.vlan_id = key->eth.vlan_id;
   1633    }
   1634
   1635    return ROCKER_OK;
   1636}
   1637
   1638static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
   1639                                 RockerTlv **flow_tlvs)
   1640{
   1641    key->width = FLOW_KEY_WIDTH(ip.tos);
   1642
   1643    key->ip.proto = 0;
   1644    key->ip.tos = 0;
   1645    mask->ip.proto = 0;
   1646    mask->ip.tos = 0;
   1647
   1648    if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO]) {
   1649        key->ip.proto =
   1650            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO]);
   1651    }
   1652    if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO_MASK]) {
   1653        mask->ip.proto =
   1654            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_PROTO_MASK]);
   1655    }
   1656    if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP]) {
   1657        key->ip.tos =
   1658            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP]);
   1659    }
   1660    if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP_MASK]) {
   1661        mask->ip.tos =
   1662            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_DSCP_MASK]);
   1663    }
   1664    if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN]) {
   1665        key->ip.tos |=
   1666            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN]) << 6;
   1667    }
   1668    if (flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) {
   1669        mask->ip.tos |=
   1670            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6;
   1671    }
   1672
   1673    return ROCKER_OK;
   1674}
   1675
   1676static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
   1677{
   1678    OfDpaFlowKey *key = &flow->key;
   1679    OfDpaFlowKey *mask = &flow->mask;
   1680    OfDpaFlowAction *action = &flow->action;
   1681    enum {
   1682        ACL_MODE_UNKNOWN,
   1683        ACL_MODE_IPV4_VLAN,
   1684        ACL_MODE_IPV6_VLAN,
   1685        ACL_MODE_IPV4_TENANT,
   1686        ACL_MODE_IPV6_TENANT,
   1687        ACL_MODE_NON_IP_VLAN,
   1688        ACL_MODE_NON_IP_TENANT,
   1689        ACL_MODE_ANY_VLAN,
   1690        ACL_MODE_ANY_TENANT,
   1691    } mode = ACL_MODE_UNKNOWN;
   1692    int err = ROCKER_OK;
   1693
   1694    if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
   1695        !flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) {
   1696        return -ROCKER_EINVAL;
   1697    }
   1698
   1699    if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID] &&
   1700        flow_tlvs[ROCKER_TLV_OF_DPA_TUNNEL_ID]) {
   1701        return -ROCKER_EINVAL;
   1702    }
   1703
   1704    key->tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
   1705    key->width = FLOW_KEY_WIDTH(eth.type);
   1706
   1707    key->in_pport = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT]);
   1708    if (flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]) {
   1709        mask->in_pport =
   1710            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT_MASK]);
   1711    }
   1712
   1713    if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) {
   1714        memcpy(key->eth.src.a,
   1715               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]),
   1716               sizeof(key->eth.src.a));
   1717    }
   1718
   1719    if (flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC_MASK]) {
   1720        memcpy(mask->eth.src.a,
   1721               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC_MASK]),
   1722               sizeof(mask->eth.src.a));
   1723    }
   1724
   1725    if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
   1726        memcpy(key->eth.dst.a,
   1727               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
   1728               sizeof(key->eth.dst.a));
   1729    }
   1730
   1731    if (flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]) {
   1732        memcpy(mask->eth.dst.a,
   1733               rocker_tlv_data(flow_tlvs[ROCKER_TLV_OF_DPA_DST_MAC_MASK]),
   1734               sizeof(mask->eth.dst.a));
   1735    }
   1736
   1737    key->eth.type = rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]);
   1738    if (key->eth.type) {
   1739        mask->eth.type = 0xffff;
   1740    }
   1741
   1742    if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
   1743        key->eth.vlan_id =
   1744            rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   1745    }
   1746
   1747    if (flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]) {
   1748        mask->eth.vlan_id =
   1749            rocker_tlv_get_u16(flow_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID_MASK]);
   1750    }
   1751
   1752    switch (ntohs(key->eth.type)) {
   1753    case 0x0000:
   1754        mode = (key->eth.vlan_id) ? ACL_MODE_ANY_VLAN : ACL_MODE_ANY_TENANT;
   1755        break;
   1756    case 0x0800:
   1757        mode = (key->eth.vlan_id) ? ACL_MODE_IPV4_VLAN : ACL_MODE_IPV4_TENANT;
   1758        break;
   1759    case 0x86dd:
   1760        mode = (key->eth.vlan_id) ? ACL_MODE_IPV6_VLAN : ACL_MODE_IPV6_TENANT;
   1761        break;
   1762    default:
   1763        mode = (key->eth.vlan_id) ? ACL_MODE_NON_IP_VLAN :
   1764                                    ACL_MODE_NON_IP_TENANT;
   1765        break;
   1766    }
   1767
   1768    /* XXX only supporting VLAN modes for now */
   1769    if (mode != ACL_MODE_IPV4_VLAN &&
   1770        mode != ACL_MODE_IPV6_VLAN &&
   1771        mode != ACL_MODE_NON_IP_VLAN &&
   1772        mode != ACL_MODE_ANY_VLAN) {
   1773        return -ROCKER_EINVAL;
   1774    }
   1775
   1776    switch (ntohs(key->eth.type)) {
   1777    case 0x0800:
   1778    case 0x86dd:
   1779        err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs);
   1780        break;
   1781    }
   1782
   1783    if (err) {
   1784        return err;
   1785    }
   1786
   1787    if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
   1788        action->write.group_id =
   1789            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
   1790    }
   1791
   1792    if (flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]) {
   1793        action->apply.copy_to_cpu =
   1794            rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_COPY_CPU_ACTION]);
   1795    }
   1796
   1797    return ROCKER_OK;
   1798}
   1799
   1800static int of_dpa_cmd_flow_add_mod(OfDpa *of_dpa, OfDpaFlow *flow,
   1801                                   RockerTlv **flow_tlvs)
   1802{
   1803    enum rocker_of_dpa_table_id tbl;
   1804    int err = ROCKER_OK;
   1805
   1806    if (!flow_tlvs[ROCKER_TLV_OF_DPA_TABLE_ID] ||
   1807        !flow_tlvs[ROCKER_TLV_OF_DPA_PRIORITY] ||
   1808        !flow_tlvs[ROCKER_TLV_OF_DPA_HARDTIME]) {
   1809        return -ROCKER_EINVAL;
   1810    }
   1811
   1812    tbl = rocker_tlv_get_le16(flow_tlvs[ROCKER_TLV_OF_DPA_TABLE_ID]);
   1813    flow->priority = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_PRIORITY]);
   1814    flow->hardtime = rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_HARDTIME]);
   1815
   1816    if (flow_tlvs[ROCKER_TLV_OF_DPA_IDLETIME]) {
   1817        if (tbl == ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT ||
   1818            tbl == ROCKER_OF_DPA_TABLE_ID_VLAN ||
   1819            tbl == ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC) {
   1820            return -ROCKER_EINVAL;
   1821        }
   1822        flow->idletime =
   1823            rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_IDLETIME]);
   1824    }
   1825
   1826    switch (tbl) {
   1827    case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
   1828        err = of_dpa_cmd_add_ig_port(flow, flow_tlvs);
   1829        break;
   1830    case ROCKER_OF_DPA_TABLE_ID_VLAN:
   1831        err = of_dpa_cmd_add_vlan(flow, flow_tlvs);
   1832        break;
   1833    case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
   1834        err = of_dpa_cmd_add_term_mac(flow, flow_tlvs);
   1835        break;
   1836    case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
   1837        err = of_dpa_cmd_add_bridging(flow, flow_tlvs);
   1838        break;
   1839    case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
   1840        err = of_dpa_cmd_add_unicast_routing(flow, flow_tlvs);
   1841        break;
   1842    case ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING:
   1843        err = of_dpa_cmd_add_multicast_routing(flow, flow_tlvs);
   1844        break;
   1845    case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
   1846        err = of_dpa_cmd_add_acl(flow, flow_tlvs);
   1847        break;
   1848    }
   1849
   1850    return err;
   1851}
   1852
   1853static int of_dpa_cmd_flow_add(OfDpa *of_dpa, uint64_t cookie,
   1854                               RockerTlv **flow_tlvs)
   1855{
   1856    OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
   1857    int err = ROCKER_OK;
   1858
   1859    if (flow) {
   1860        return -ROCKER_EEXIST;
   1861    }
   1862
   1863    flow = of_dpa_flow_alloc(cookie);
   1864
   1865    err = of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs);
   1866    if (err) {
   1867        g_free(flow);
   1868        return err;
   1869    }
   1870
   1871    return of_dpa_flow_add(of_dpa, flow);
   1872}
   1873
   1874static int of_dpa_cmd_flow_mod(OfDpa *of_dpa, uint64_t cookie,
   1875                               RockerTlv **flow_tlvs)
   1876{
   1877    OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
   1878
   1879    if (!flow) {
   1880        return -ROCKER_ENOENT;
   1881    }
   1882
   1883    return of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs);
   1884}
   1885
   1886static int of_dpa_cmd_flow_del(OfDpa *of_dpa, uint64_t cookie)
   1887{
   1888    OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
   1889
   1890    if (!flow) {
   1891        return -ROCKER_ENOENT;
   1892    }
   1893
   1894    of_dpa_flow_del(of_dpa, flow);
   1895
   1896    return ROCKER_OK;
   1897}
   1898
   1899static int of_dpa_cmd_flow_get_stats(OfDpa *of_dpa, uint64_t cookie,
   1900                                     struct desc_info *info, char *buf)
   1901{
   1902    OfDpaFlow *flow = of_dpa_flow_find(of_dpa, cookie);
   1903    size_t tlv_size;
   1904    int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
   1905    int pos;
   1906
   1907    if (!flow) {
   1908        return -ROCKER_ENOENT;
   1909    }
   1910
   1911    tlv_size = rocker_tlv_total_size(sizeof(uint32_t)) +  /* duration */
   1912               rocker_tlv_total_size(sizeof(uint64_t)) +  /* rx_pkts */
   1913               rocker_tlv_total_size(sizeof(uint64_t));   /* tx_ptks */
   1914
   1915    if (tlv_size > desc_buf_size(info)) {
   1916        return -ROCKER_EMSGSIZE;
   1917    }
   1918
   1919    pos = 0;
   1920    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION,
   1921                        (int32_t)(now - flow->stats.install_time));
   1922    rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS,
   1923                        flow->stats.rx_pkts);
   1924    rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS,
   1925                        flow->stats.tx_pkts);
   1926
   1927    return desc_set_buf(info, tlv_size);
   1928}
   1929
   1930static int of_dpa_flow_cmd(OfDpa *of_dpa, struct desc_info *info,
   1931                           char *buf, uint16_t cmd,
   1932                           RockerTlv **flow_tlvs)
   1933{
   1934    uint64_t cookie;
   1935
   1936    if (!flow_tlvs[ROCKER_TLV_OF_DPA_COOKIE]) {
   1937        return -ROCKER_EINVAL;
   1938    }
   1939
   1940    cookie = rocker_tlv_get_le64(flow_tlvs[ROCKER_TLV_OF_DPA_COOKIE]);
   1941
   1942    switch (cmd) {
   1943    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
   1944        return of_dpa_cmd_flow_add(of_dpa, cookie, flow_tlvs);
   1945    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
   1946        return of_dpa_cmd_flow_mod(of_dpa, cookie, flow_tlvs);
   1947    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
   1948        return of_dpa_cmd_flow_del(of_dpa, cookie);
   1949    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
   1950        return of_dpa_cmd_flow_get_stats(of_dpa, cookie, info, buf);
   1951    }
   1952
   1953    return -ROCKER_ENOTSUP;
   1954}
   1955
   1956static int of_dpa_cmd_add_l2_interface(OfDpaGroup *group,
   1957                                       RockerTlv **group_tlvs)
   1958{
   1959    if (!group_tlvs[ROCKER_TLV_OF_DPA_OUT_PPORT] ||
   1960        !group_tlvs[ROCKER_TLV_OF_DPA_POP_VLAN]) {
   1961        return -ROCKER_EINVAL;
   1962    }
   1963
   1964    group->l2_interface.out_pport =
   1965        rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_OUT_PPORT]);
   1966    group->l2_interface.pop_vlan =
   1967        rocker_tlv_get_u8(group_tlvs[ROCKER_TLV_OF_DPA_POP_VLAN]);
   1968
   1969    return ROCKER_OK;
   1970}
   1971
   1972static int of_dpa_cmd_add_l2_rewrite(OfDpa *of_dpa, OfDpaGroup *group,
   1973                                     RockerTlv **group_tlvs)
   1974{
   1975    OfDpaGroup *l2_interface_group;
   1976
   1977    if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]) {
   1978        return -ROCKER_EINVAL;
   1979    }
   1980
   1981    group->l2_rewrite.group_id =
   1982        rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]);
   1983
   1984    l2_interface_group = of_dpa_group_find(of_dpa, group->l2_rewrite.group_id);
   1985    if (!l2_interface_group ||
   1986        ROCKER_GROUP_TYPE_GET(l2_interface_group->id) !=
   1987                              ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) {
   1988        DPRINTF("l2 rewrite group needs a valid l2 interface group\n");
   1989        return -ROCKER_EINVAL;
   1990    }
   1991
   1992    if (group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) {
   1993        memcpy(group->l2_rewrite.src_mac.a,
   1994               rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]),
   1995               sizeof(group->l2_rewrite.src_mac.a));
   1996    }
   1997
   1998    if (group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
   1999        memcpy(group->l2_rewrite.dst_mac.a,
   2000               rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
   2001               sizeof(group->l2_rewrite.dst_mac.a));
   2002    }
   2003
   2004    if (group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
   2005        group->l2_rewrite.vlan_id =
   2006            rocker_tlv_get_u16(group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   2007        if (ROCKER_GROUP_VLAN_GET(l2_interface_group->id) !=
   2008            (ntohs(group->l2_rewrite.vlan_id) & VLAN_VID_MASK)) {
   2009            DPRINTF("Set VLAN ID must be same as L2 interface group\n");
   2010            return -ROCKER_EINVAL;
   2011        }
   2012    }
   2013
   2014    return ROCKER_OK;
   2015}
   2016
   2017static int of_dpa_cmd_add_l2_flood(OfDpa *of_dpa, OfDpaGroup *group,
   2018                                   RockerTlv **group_tlvs)
   2019{
   2020    OfDpaGroup *l2_group;
   2021    RockerTlv **tlvs;
   2022    int err;
   2023    int i;
   2024
   2025    if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT] ||
   2026        !group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]) {
   2027        return -ROCKER_EINVAL;
   2028    }
   2029
   2030    group->l2_flood.group_count =
   2031        rocker_tlv_get_le16(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT]);
   2032
   2033    tlvs = g_new0(RockerTlv *, group->l2_flood.group_count + 1);
   2034
   2035    g_free(group->l2_flood.group_ids);
   2036    group->l2_flood.group_ids =
   2037        g_new0(uint32_t, group->l2_flood.group_count);
   2038
   2039    rocker_tlv_parse_nested(tlvs, group->l2_flood.group_count,
   2040                            group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]);
   2041
   2042    for (i = 0; i < group->l2_flood.group_count; i++) {
   2043        group->l2_flood.group_ids[i] = rocker_tlv_get_le32(tlvs[i + 1]);
   2044    }
   2045
   2046    /* All of the L2 interface groups referenced by the L2 flood
   2047     * must have same VLAN
   2048     */
   2049
   2050    for (i = 0; i < group->l2_flood.group_count; i++) {
   2051        l2_group = of_dpa_group_find(of_dpa, group->l2_flood.group_ids[i]);
   2052        if (!l2_group) {
   2053            continue;
   2054        }
   2055        if ((ROCKER_GROUP_TYPE_GET(l2_group->id) ==
   2056             ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) &&
   2057            (ROCKER_GROUP_VLAN_GET(l2_group->id) !=
   2058             ROCKER_GROUP_VLAN_GET(group->id))) {
   2059            DPRINTF("l2 interface group 0x%08x VLAN doesn't match l2 "
   2060                    "flood group 0x%08x\n",
   2061                    group->l2_flood.group_ids[i], group->id);
   2062            err = -ROCKER_EINVAL;
   2063            goto err_out;
   2064        }
   2065    }
   2066
   2067    g_free(tlvs);
   2068    return ROCKER_OK;
   2069
   2070err_out:
   2071    group->l2_flood.group_count = 0;
   2072    g_free(group->l2_flood.group_ids);
   2073    g_free(tlvs);
   2074
   2075    return err;
   2076}
   2077
   2078static int of_dpa_cmd_add_l3_unicast(OfDpaGroup *group, RockerTlv **group_tlvs)
   2079{
   2080    if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]) {
   2081        return -ROCKER_EINVAL;
   2082    }
   2083
   2084    group->l3_unicast.group_id =
   2085        rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID_LOWER]);
   2086
   2087    if (group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]) {
   2088        memcpy(group->l3_unicast.src_mac.a,
   2089               rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_SRC_MAC]),
   2090               sizeof(group->l3_unicast.src_mac.a));
   2091    }
   2092
   2093    if (group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]) {
   2094        memcpy(group->l3_unicast.dst_mac.a,
   2095               rocker_tlv_data(group_tlvs[ROCKER_TLV_OF_DPA_DST_MAC]),
   2096               sizeof(group->l3_unicast.dst_mac.a));
   2097    }
   2098
   2099    if (group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]) {
   2100        group->l3_unicast.vlan_id =
   2101            rocker_tlv_get_u16(group_tlvs[ROCKER_TLV_OF_DPA_VLAN_ID]);
   2102    }
   2103
   2104    if (group_tlvs[ROCKER_TLV_OF_DPA_TTL_CHECK]) {
   2105        group->l3_unicast.ttl_check =
   2106            rocker_tlv_get_u8(group_tlvs[ROCKER_TLV_OF_DPA_TTL_CHECK]);
   2107    }
   2108
   2109    return ROCKER_OK;
   2110}
   2111
   2112static int of_dpa_cmd_group_do(OfDpa *of_dpa, uint32_t group_id,
   2113                               OfDpaGroup *group, RockerTlv **group_tlvs)
   2114{
   2115    uint8_t type = ROCKER_GROUP_TYPE_GET(group_id);
   2116
   2117    switch (type) {
   2118    case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
   2119        return of_dpa_cmd_add_l2_interface(group, group_tlvs);
   2120    case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
   2121        return of_dpa_cmd_add_l2_rewrite(of_dpa, group, group_tlvs);
   2122    case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
   2123    /* Treat L2 multicast group same as a L2 flood group */
   2124    case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
   2125        return of_dpa_cmd_add_l2_flood(of_dpa, group, group_tlvs);
   2126    case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
   2127        return of_dpa_cmd_add_l3_unicast(group, group_tlvs);
   2128    }
   2129
   2130    return -ROCKER_ENOTSUP;
   2131}
   2132
   2133static int of_dpa_cmd_group_add(OfDpa *of_dpa, uint32_t group_id,
   2134                                RockerTlv **group_tlvs)
   2135{
   2136    OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id);
   2137    int err;
   2138
   2139    if (group) {
   2140        return -ROCKER_EEXIST;
   2141    }
   2142
   2143    group = of_dpa_group_alloc(group_id);
   2144
   2145    err = of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs);
   2146    if (err) {
   2147        goto err_cmd_add;
   2148    }
   2149
   2150    err = of_dpa_group_add(of_dpa, group);
   2151    if (err) {
   2152        goto err_cmd_add;
   2153    }
   2154
   2155    return ROCKER_OK;
   2156
   2157err_cmd_add:
   2158    g_free(group);
   2159    return err;
   2160}
   2161
   2162static int of_dpa_cmd_group_mod(OfDpa *of_dpa, uint32_t group_id,
   2163                                RockerTlv **group_tlvs)
   2164{
   2165    OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id);
   2166
   2167    if (!group) {
   2168        return -ROCKER_ENOENT;
   2169    }
   2170
   2171    return of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs);
   2172}
   2173
   2174static int of_dpa_cmd_group_del(OfDpa *of_dpa, uint32_t group_id)
   2175{
   2176    OfDpaGroup *group = of_dpa_group_find(of_dpa, group_id);
   2177
   2178    if (!group) {
   2179        return -ROCKER_ENOENT;
   2180    }
   2181
   2182    return of_dpa_group_del(of_dpa, group);
   2183}
   2184
   2185static int of_dpa_cmd_group_get_stats(OfDpa *of_dpa, uint32_t group_id,
   2186                                      struct desc_info *info, char *buf)
   2187{
   2188    return -ROCKER_ENOTSUP;
   2189}
   2190
   2191static int of_dpa_group_cmd(OfDpa *of_dpa, struct desc_info *info,
   2192                            char *buf, uint16_t cmd, RockerTlv **group_tlvs)
   2193{
   2194    uint32_t group_id;
   2195
   2196    if (!group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
   2197        return -ROCKER_EINVAL;
   2198    }
   2199
   2200    group_id = rocker_tlv_get_le32(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
   2201
   2202    switch (cmd) {
   2203    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
   2204        return of_dpa_cmd_group_add(of_dpa, group_id, group_tlvs);
   2205    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
   2206        return of_dpa_cmd_group_mod(of_dpa, group_id, group_tlvs);
   2207    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
   2208        return of_dpa_cmd_group_del(of_dpa, group_id);
   2209    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
   2210        return of_dpa_cmd_group_get_stats(of_dpa, group_id, info, buf);
   2211    }
   2212
   2213    return -ROCKER_ENOTSUP;
   2214}
   2215
   2216static int of_dpa_cmd(World *world, struct desc_info *info,
   2217                      char *buf, uint16_t cmd, RockerTlv *cmd_info_tlv)
   2218{
   2219    OfDpa *of_dpa = world_private(world);
   2220    RockerTlv *tlvs[ROCKER_TLV_OF_DPA_MAX + 1];
   2221
   2222    rocker_tlv_parse_nested(tlvs, ROCKER_TLV_OF_DPA_MAX, cmd_info_tlv);
   2223
   2224    switch (cmd) {
   2225    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
   2226    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
   2227    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
   2228    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
   2229        return of_dpa_flow_cmd(of_dpa, info, buf, cmd, tlvs);
   2230    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
   2231    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
   2232    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
   2233    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
   2234        return of_dpa_group_cmd(of_dpa, info, buf, cmd, tlvs);
   2235    }
   2236
   2237    return -ROCKER_ENOTSUP;
   2238}
   2239
   2240static gboolean rocker_int64_equal(gconstpointer v1, gconstpointer v2)
   2241{
   2242    return *((const uint64_t *)v1) == *((const uint64_t *)v2);
   2243}
   2244
   2245static guint rocker_int64_hash(gconstpointer v)
   2246{
   2247    return (guint)*(const uint64_t *)v;
   2248}
   2249
   2250static int of_dpa_init(World *world)
   2251{
   2252    OfDpa *of_dpa = world_private(world);
   2253
   2254    of_dpa->world = world;
   2255
   2256    of_dpa->flow_tbl = g_hash_table_new_full(rocker_int64_hash,
   2257                                             rocker_int64_equal,
   2258                                             NULL, g_free);
   2259    if (!of_dpa->flow_tbl) {
   2260        return -ENOMEM;
   2261    }
   2262
   2263    of_dpa->group_tbl = g_hash_table_new_full(g_int_hash, g_int_equal,
   2264                                              NULL, g_free);
   2265    if (!of_dpa->group_tbl) {
   2266        goto err_group_tbl;
   2267    }
   2268
   2269    /* XXX hardcode some artificial table max values */
   2270    of_dpa->flow_tbl_max_size = 100;
   2271    of_dpa->group_tbl_max_size = 100;
   2272
   2273    return 0;
   2274
   2275err_group_tbl:
   2276    g_hash_table_destroy(of_dpa->flow_tbl);
   2277    return -ENOMEM;
   2278}
   2279
   2280static void of_dpa_uninit(World *world)
   2281{
   2282    OfDpa *of_dpa = world_private(world);
   2283
   2284    g_hash_table_destroy(of_dpa->group_tbl);
   2285    g_hash_table_destroy(of_dpa->flow_tbl);
   2286}
   2287
   2288struct of_dpa_flow_fill_context {
   2289    RockerOfDpaFlowList *list;
   2290    uint32_t tbl_id;
   2291};
   2292
   2293static void of_dpa_flow_fill(void *cookie, void *value, void *user_data)
   2294{
   2295    struct of_dpa_flow *flow = value;
   2296    struct of_dpa_flow_key *key = &flow->key;
   2297    struct of_dpa_flow_key *mask = &flow->mask;
   2298    struct of_dpa_flow_fill_context *flow_context = user_data;
   2299    RockerOfDpaFlow *nflow;
   2300    RockerOfDpaFlowKey *nkey;
   2301    RockerOfDpaFlowMask *nmask;
   2302    RockerOfDpaFlowAction *naction;
   2303
   2304    if (flow_context->tbl_id != -1 &&
   2305        flow_context->tbl_id != key->tbl_id) {
   2306        return;
   2307    }
   2308
   2309    nflow = g_malloc0(sizeof(*nflow));
   2310    nkey = nflow->key = g_malloc0(sizeof(*nkey));
   2311    nmask = nflow->mask = g_malloc0(sizeof(*nmask));
   2312    naction = nflow->action = g_malloc0(sizeof(*naction));
   2313
   2314    nflow->cookie = flow->cookie;
   2315    nflow->hits = flow->stats.hits;
   2316    nkey->priority = flow->priority;
   2317    nkey->tbl_id = key->tbl_id;
   2318
   2319    if (key->in_pport || mask->in_pport) {
   2320        nkey->has_in_pport = true;
   2321        nkey->in_pport = key->in_pport;
   2322    }
   2323
   2324    if (nkey->has_in_pport && mask->in_pport != 0xffffffff) {
   2325        nmask->has_in_pport = true;
   2326        nmask->in_pport = mask->in_pport;
   2327    }
   2328
   2329    if (key->eth.vlan_id || mask->eth.vlan_id) {
   2330        nkey->has_vlan_id = true;
   2331        nkey->vlan_id = ntohs(key->eth.vlan_id);
   2332    }
   2333
   2334    if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) {
   2335        nmask->has_vlan_id = true;
   2336        nmask->vlan_id = ntohs(mask->eth.vlan_id);
   2337    }
   2338
   2339    if (key->tunnel_id || mask->tunnel_id) {
   2340        nkey->has_tunnel_id = true;
   2341        nkey->tunnel_id = key->tunnel_id;
   2342    }
   2343
   2344    if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) {
   2345        nmask->has_tunnel_id = true;
   2346        nmask->tunnel_id = mask->tunnel_id;
   2347    }
   2348
   2349    if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) ||
   2350        memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) {
   2351        nkey->has_eth_src = true;
   2352        nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a);
   2353    }
   2354
   2355    if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) {
   2356        nmask->has_eth_src = true;
   2357        nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a);
   2358    }
   2359
   2360    if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) ||
   2361        memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) {
   2362        nkey->has_eth_dst = true;
   2363        nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a);
   2364    }
   2365
   2366    if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) {
   2367        nmask->has_eth_dst = true;
   2368        nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a);
   2369    }
   2370
   2371    if (key->eth.type) {
   2372
   2373        nkey->has_eth_type = true;
   2374        nkey->eth_type = ntohs(key->eth.type);
   2375
   2376        switch (ntohs(key->eth.type)) {
   2377        case 0x0800:
   2378        case 0x86dd:
   2379            if (key->ip.proto || mask->ip.proto) {
   2380                nkey->has_ip_proto = true;
   2381                nkey->ip_proto = key->ip.proto;
   2382            }
   2383            if (nkey->has_ip_proto && mask->ip.proto != 0xff) {
   2384                nmask->has_ip_proto = true;
   2385                nmask->ip_proto = mask->ip.proto;
   2386            }
   2387            if (key->ip.tos || mask->ip.tos) {
   2388                nkey->has_ip_tos = true;
   2389                nkey->ip_tos = key->ip.tos;
   2390            }
   2391            if (nkey->has_ip_tos && mask->ip.tos != 0xff) {
   2392                nmask->has_ip_tos = true;
   2393                nmask->ip_tos = mask->ip.tos;
   2394            }
   2395            break;
   2396        }
   2397
   2398        switch (ntohs(key->eth.type)) {
   2399        case 0x0800:
   2400            if (key->ipv4.addr.dst || mask->ipv4.addr.dst) {
   2401                char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst);
   2402                int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst);
   2403                nkey->has_ip_dst = true;
   2404                nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len);
   2405            }
   2406            break;
   2407        }
   2408    }
   2409
   2410    if (flow->action.goto_tbl) {
   2411        naction->has_goto_tbl = true;
   2412        naction->goto_tbl = flow->action.goto_tbl;
   2413    }
   2414
   2415    if (flow->action.write.group_id) {
   2416        naction->has_group_id = true;
   2417        naction->group_id = flow->action.write.group_id;
   2418    }
   2419
   2420    if (flow->action.apply.new_vlan_id) {
   2421        naction->has_new_vlan_id = true;
   2422        naction->new_vlan_id = flow->action.apply.new_vlan_id;
   2423    }
   2424
   2425    QAPI_LIST_PREPEND(flow_context->list, nflow);
   2426}
   2427
   2428RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
   2429                                                   bool has_tbl_id,
   2430                                                   uint32_t tbl_id,
   2431                                                   Error **errp)
   2432{
   2433    struct rocker *r;
   2434    struct world *w;
   2435    struct of_dpa *of_dpa;
   2436    struct of_dpa_flow_fill_context fill_context = {
   2437        .list = NULL,
   2438        .tbl_id = tbl_id,
   2439    };
   2440
   2441    r = rocker_find(name);
   2442    if (!r) {
   2443        error_setg(errp, "rocker %s not found", name);
   2444        return NULL;
   2445    }
   2446
   2447    w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
   2448    if (!w) {
   2449        error_setg(errp, "rocker %s doesn't have OF-DPA world", name);
   2450        return NULL;
   2451    }
   2452
   2453    of_dpa = world_private(w);
   2454
   2455    g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context);
   2456
   2457    return fill_context.list;
   2458}
   2459
   2460struct of_dpa_group_fill_context {
   2461    RockerOfDpaGroupList *list;
   2462    uint8_t type;
   2463};
   2464
   2465static void of_dpa_group_fill(void *key, void *value, void *user_data)
   2466{
   2467    struct of_dpa_group *group = value;
   2468    struct of_dpa_group_fill_context *flow_context = user_data;
   2469    RockerOfDpaGroup *ngroup;
   2470    int i;
   2471
   2472    if (flow_context->type != 9 &&
   2473        flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) {
   2474        return;
   2475    }
   2476
   2477    ngroup = g_malloc0(sizeof(*ngroup));
   2478
   2479    ngroup->id = group->id;
   2480
   2481    ngroup->type = ROCKER_GROUP_TYPE_GET(group->id);
   2482
   2483    switch (ngroup->type) {
   2484    case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
   2485        ngroup->has_vlan_id = true;
   2486        ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
   2487        ngroup->has_pport = true;
   2488        ngroup->pport = ROCKER_GROUP_PORT_GET(group->id);
   2489        ngroup->has_out_pport = true;
   2490        ngroup->out_pport = group->l2_interface.out_pport;
   2491        ngroup->has_pop_vlan = true;
   2492        ngroup->pop_vlan = group->l2_interface.pop_vlan;
   2493        break;
   2494    case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
   2495        ngroup->has_index = true;
   2496        ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
   2497        ngroup->has_group_id = true;
   2498        ngroup->group_id = group->l2_rewrite.group_id;
   2499        if (group->l2_rewrite.vlan_id) {
   2500            ngroup->has_set_vlan_id = true;
   2501            ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id);
   2502        }
   2503        if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) {
   2504            ngroup->has_set_eth_src = true;
   2505            ngroup->set_eth_src =
   2506                qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a);
   2507        }
   2508        if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) {
   2509            ngroup->has_set_eth_dst = true;
   2510            ngroup->set_eth_dst =
   2511                qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a);
   2512        }
   2513        break;
   2514    case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
   2515    case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
   2516        ngroup->has_vlan_id = true;
   2517        ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
   2518        ngroup->has_index = true;
   2519        ngroup->index = ROCKER_GROUP_INDEX_GET(group->id);
   2520        for (i = 0; i < group->l2_flood.group_count; i++) {
   2521            ngroup->has_group_ids = true;
   2522            QAPI_LIST_PREPEND(ngroup->group_ids, group->l2_flood.group_ids[i]);
   2523        }
   2524        break;
   2525    case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
   2526        ngroup->has_index = true;
   2527        ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
   2528        ngroup->has_group_id = true;
   2529        ngroup->group_id = group->l3_unicast.group_id;
   2530        if (group->l3_unicast.vlan_id) {
   2531            ngroup->has_set_vlan_id = true;
   2532            ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id);
   2533        }
   2534        if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) {
   2535            ngroup->has_set_eth_src = true;
   2536            ngroup->set_eth_src =
   2537                qemu_mac_strdup_printf(group->l3_unicast.src_mac.a);
   2538        }
   2539        if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) {
   2540            ngroup->has_set_eth_dst = true;
   2541            ngroup->set_eth_dst =
   2542                qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a);
   2543        }
   2544        if (group->l3_unicast.ttl_check) {
   2545            ngroup->has_ttl_check = true;
   2546            ngroup->ttl_check = group->l3_unicast.ttl_check;
   2547        }
   2548        break;
   2549    }
   2550
   2551    QAPI_LIST_PREPEND(flow_context->list, ngroup);
   2552}
   2553
   2554RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
   2555                                                     bool has_type,
   2556                                                     uint8_t type,
   2557                                                     Error **errp)
   2558{
   2559    struct rocker *r;
   2560    struct world *w;
   2561    struct of_dpa *of_dpa;
   2562    struct of_dpa_group_fill_context fill_context = {
   2563        .list = NULL,
   2564        .type = type,
   2565    };
   2566
   2567    r = rocker_find(name);
   2568    if (!r) {
   2569        error_setg(errp, "rocker %s not found", name);
   2570        return NULL;
   2571    }
   2572
   2573    w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
   2574    if (!w) {
   2575        error_setg(errp, "rocker %s doesn't have OF-DPA world", name);
   2576        return NULL;
   2577    }
   2578
   2579    of_dpa = world_private(w);
   2580
   2581    g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context);
   2582
   2583    return fill_context.list;
   2584}
   2585
   2586static WorldOps of_dpa_ops = {
   2587    .name = "ofdpa",
   2588    .init = of_dpa_init,
   2589    .uninit = of_dpa_uninit,
   2590    .ig = of_dpa_ig,
   2591    .cmd = of_dpa_cmd,
   2592};
   2593
   2594World *of_dpa_world_alloc(Rocker *r)
   2595{
   2596    return world_alloc(r, sizeof(OfDpa), ROCKER_WORLD_TYPE_OF_DPA, &of_dpa_ops);
   2597}