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