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