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