79 * We will use this same AVL comparison function for many of these structures.
80 */
81 int
82 vxlnat_tree_plus_in6_cmp(const void *first, const void *second)
83 {
84 in6_addr_t *firstaddr, *secondaddr;
85 int ret;
86
87 firstaddr = (in6_addr_t *)(((avl_node_t *)first) + 1);
88 secondaddr = (in6_addr_t *)(((avl_node_t *)second) + 1);
89
90 ret = memcmp(firstaddr, secondaddr, sizeof (in6_addr_t));
91 if (ret > 0)
92 return (1);
93 if (ret < 0)
94 return (-1);
95 return (0);
96 }
97
98 /*
99 * Find-and-reference-hold a vnet. If none present, create one.
100 * "vnetid" MUST be in wire-order and its one byte cleared.
101 */
102 vxlnat_vnet_t *
103 vxlnat_get_vnet(uint32_t vnetid, boolean_t create_on_miss)
104 {
105 vxlnat_vnet_t *vnet, searcher;
106 avl_index_t where;
107
108 /* Cheesy, but we KNOW vxnv_vnetid is the only thing checked. */
109 searcher.vxnv_vnetid = vnetid;
110
111 rw_enter(&vxlnat_vnet_lock, create_on_miss ? RW_WRITER : RW_READER);
112 vnet = (vxlnat_vnet_t *)avl_find(&vxlnat_vnets, &searcher, &where);
113 if (vnet == NULL && create_on_miss) {
114 vnet = kmem_zalloc(sizeof (*vnet), KM_SLEEP);
115 /* KM_SLEEP means non-NULL guaranteed. */
116 vnet->vxnv_refcount = 1; /* Internment reference. */
117 vnet->vxnv_vnetid = vnetid;
118 /* Initialize 1-1 mappings... */
119 rw_init(&vnet->vxnv_fixed_lock, NULL, RW_DRIVER, NULL);
120 avl_create(&vnet->vxnv_fixed_ips, vxlnat_tree_plus_in6_cmp,
121 sizeof (vxlnat_fixed_t), 0);
122 /* Initialize NAT rules. (NAT mutex is zeroed-out.) */
123 list_create(&vnet->vxnv_rules, sizeof (vxlnat_rule_t), 0);
124 #ifdef notyet
125 /* XXX KEBE SAYS INITIALIZE NAT flows... */
126 #endif /* notyet */
127 /*
128 * Initialize remote VXLAN destination cache.
129 * (remotes mutex is zeroed-out.)
130 */
131 avl_create(&vnet->vxnv_remotes, vxlnat_tree_plus_in6_cmp,
132 sizeof (vxlnat_remote_t), 0);
133
134 avl_insert(&vxlnat_vnets, vnet, where);
135 }
136 if (vnet != NULL)
137 VXNV_REFHOLD(vnet); /* Caller's reference. */
138 rw_exit(&vxlnat_vnet_lock);
139
140 return (vnet);
141 }
142
143 void
144 vxlnat_vnet_free(vxlnat_vnet_t *vnet)
145 {
146 /* XXX KEBE SAYS FILL ME IN */
417 * other {zones,machines} without triggering DAD.
418 */
419 if (ire->ire_type != IRE_LOCAL) {
420 ire_refrele(ire);
421 kmem_free(fixed, sizeof (*fixed));
422 rc = EADDRNOTAVAIL; /* XXX KEBE ASKS different errno? */
423 goto fail;
424 }
425
426 /* Put the 1-1 mapping in place. */
427 rw_enter(&vnet->vxnv_fixed_lock, RW_WRITER);
428 if (avl_find(&vnet->vxnv_fixed_ips, fixed, &where) != NULL) {
429 /* Oh crap, we have an internal IP mapped already. */
430 ire_refrele(ire);
431 kmem_free(fixed, sizeof (*fixed));
432 rc = EEXIST;
433 } else {
434 avl_insert(&vnet->vxnv_fixed_ips, fixed, where);
435 rc = 0;
436 /*
437 * CHEESY USE OF POINTERS WARNING: I'm going to use
438 * ire_dep_children for this IRE_LOCAL as a backpointer to
439 * this 'fixed'. This'll allow rapid packet processing.
440 * Inspection seems to indicate that IRE_LOCAL ires NEVER use
441 * the ire_dep* pointers, so we'll use one (and independent of
442 * ip_stack_t's ips_ire_dep_lock as well). If I'm wrong,
443 * fix it here and add a new pointer in ip.h for ire_t.
444 */
445 ire->ire_dep_sib_next = (ire_t *)fixed;
446 /* and then rewire the ire receive and send functions. */
447 if (ire->ire_ipversion == IPV4_VERSION) {
448 ire->ire_recvfn = vxlnat_fixed_ire_recv_v4;
449 ire->ire_sendfn = vxlnat_fixed_ire_send_v4;
450 } else {
451 ASSERT(ire->ire_ipversion == IPV6_VERSION);
452 ire->ire_recvfn = vxlnat_fixed_ire_recv_v6;
453 ire->ire_sendfn = vxlnat_fixed_ire_send_v6;
454 }
455 VXNF_REFHOLD(fixed); /* ire holds us too... */
456 fixed->vxnf_ire = ire;
457 /*
458 * XXX KEBE SAYS CHEESY HACK:
459 */
460 if (!(ire->ire_ill->ill_flags & ILLF_ROUTER)) {
461 fixed->vxnf_clear_router = B_TRUE;
462 ire->ire_ill->ill_flags |= ILLF_ROUTER;
463 } else {
464 /* Just so we're clear... */
465 fixed->vxnf_clear_router = B_FALSE;
466 }
467 }
468 rw_exit(&vnet->vxnv_fixed_lock);
469
470 fail:
471 if (rc != 0)
472 vxlnat_public_rele(&vxnm->vxnm_public);
473
474 return (rc);
475 }
476
477 static void
478 vxlnat_rule_to_msg(vxn_msg_t *msg, vxlnat_rule_t *rule)
479 {
480 msg->vxnm_type = VXNM_RULE;
481 msg->vxnm_vnetid = VXLAN_ID_NTOH(rule->vxnr_vnet->vxnv_vnetid);
482 msg->vxnm_prefix = rule->vxnr_prefix;
483 msg->vxnm_vlanid = ntohs(rule->vxnr_vlanid);
484 bcopy(rule->vxnr_myether, msg->vxnm_ether_addr, ETHERADDRL);
485 msg->vxnm_public = rule->vxnr_pubaddr;
486 msg->vxnm_private = rule->vxnr_myaddr;
|
79 * We will use this same AVL comparison function for many of these structures.
80 */
81 int
82 vxlnat_tree_plus_in6_cmp(const void *first, const void *second)
83 {
84 in6_addr_t *firstaddr, *secondaddr;
85 int ret;
86
87 firstaddr = (in6_addr_t *)(((avl_node_t *)first) + 1);
88 secondaddr = (in6_addr_t *)(((avl_node_t *)second) + 1);
89
90 ret = memcmp(firstaddr, secondaddr, sizeof (in6_addr_t));
91 if (ret > 0)
92 return (1);
93 if (ret < 0)
94 return (-1);
95 return (0);
96 }
97
98 /*
99 * Comparison function for NAT flow.
100 */
101 static int
102 vxlnat_flow_cmp_v4(const void *first, const void *second)
103 {
104 vxlnat_flow_t *first_flow = (vxlnat_flow_t *)first;
105 vxlnat_flow_t *second_flow = (vxlnat_flow_t *)second;
106 uint64_t firstaddrs, secondaddrs, firstportproto, secondportproto;
107
108 firstaddrs = first_flow->vxnfl_src._S6_un._S6_u32[3] |
109 (((uint64_t)first_flow->vxnfl_dst._S6_un._S6_u32[3]) << 32ULL);
110 secondaddrs = second_flow->vxnfl_src._S6_un._S6_u32[3] |
111 (((uint64_t)second_flow->vxnfl_dst._S6_un._S6_u32[3]) << 32ULL);
112 firstportproto = first_flow->vxnfl_ports |
113 (((uint64_t)first_flow->vxnfl_protocol) << 32ULL);
114 secondportproto = second_flow->vxnfl_ports |
115 (((uint64_t)second_flow->vxnfl_protocol) << 32ULL);
116
117 if (firstaddrs > secondaddrs)
118 return (1);
119 else if (firstaddrs < secondaddrs)
120 return (-1);
121 else if (firstportproto > secondportproto)
122 return (1);
123 else if (firstportproto < secondportproto)
124 return (-1);
125
126 return (0);
127 }
128
129 /*
130 * Find-and-reference-hold a vnet. If none present, create one.
131 * "vnetid" MUST be in wire-order and its one byte cleared.
132 */
133 vxlnat_vnet_t *
134 vxlnat_get_vnet(uint32_t vnetid, boolean_t create_on_miss)
135 {
136 vxlnat_vnet_t *vnet, searcher;
137 avl_index_t where;
138
139 /* Cheesy, but we KNOW vxnv_vnetid is the only thing checked. */
140 searcher.vxnv_vnetid = vnetid;
141
142 rw_enter(&vxlnat_vnet_lock, create_on_miss ? RW_WRITER : RW_READER);
143 vnet = (vxlnat_vnet_t *)avl_find(&vxlnat_vnets, &searcher, &where);
144 if (vnet == NULL && create_on_miss) {
145 vnet = kmem_zalloc(sizeof (*vnet), KM_SLEEP);
146 /* KM_SLEEP means non-NULL guaranteed. */
147 vnet->vxnv_refcount = 1; /* Internment reference. */
148 vnet->vxnv_vnetid = vnetid;
149 /* Initialize 1-1 mappings... */
150 rw_init(&vnet->vxnv_fixed_lock, NULL, RW_DRIVER, NULL);
151 avl_create(&vnet->vxnv_fixed_ips, vxlnat_tree_plus_in6_cmp,
152 sizeof (vxlnat_fixed_t), 0);
153 /* Initialize NAT rules. (NAT mutex is zeroed-out.) */
154 list_create(&vnet->vxnv_rules, sizeof (vxlnat_rule_t), 0);
155
156 /* Initialize NAT flows... */
157 rw_init(&vnet->vxnv_flowv4_lock, NULL, RW_DRIVER, NULL);
158 avl_create(&vnet->vxnv_flows_v4, vxlnat_flow_cmp_v4,
159 sizeof (vxlnat_flow_t), 0);
160
161 /*
162 * Initialize remote VXLAN destination cache.
163 * (remotes mutex is zeroed-out.)
164 */
165 avl_create(&vnet->vxnv_remotes, vxlnat_tree_plus_in6_cmp,
166 sizeof (vxlnat_remote_t), 0);
167
168 avl_insert(&vxlnat_vnets, vnet, where);
169 }
170 if (vnet != NULL)
171 VXNV_REFHOLD(vnet); /* Caller's reference. */
172 rw_exit(&vxlnat_vnet_lock);
173
174 return (vnet);
175 }
176
177 void
178 vxlnat_vnet_free(vxlnat_vnet_t *vnet)
179 {
180 /* XXX KEBE SAYS FILL ME IN */
451 * other {zones,machines} without triggering DAD.
452 */
453 if (ire->ire_type != IRE_LOCAL) {
454 ire_refrele(ire);
455 kmem_free(fixed, sizeof (*fixed));
456 rc = EADDRNOTAVAIL; /* XXX KEBE ASKS different errno? */
457 goto fail;
458 }
459
460 /* Put the 1-1 mapping in place. */
461 rw_enter(&vnet->vxnv_fixed_lock, RW_WRITER);
462 if (avl_find(&vnet->vxnv_fixed_ips, fixed, &where) != NULL) {
463 /* Oh crap, we have an internal IP mapped already. */
464 ire_refrele(ire);
465 kmem_free(fixed, sizeof (*fixed));
466 rc = EEXIST;
467 } else {
468 avl_insert(&vnet->vxnv_fixed_ips, fixed, where);
469 rc = 0;
470 /*
471 * ODD USE OF POINTERS WARNING: I'm going to use
472 * ire_dep_sib_next for this IRE_LOCAL as a backpointer to
473 * this 'fixed'. This'll allow rapid packet processing.
474 * Inspection seems to indicate that IRE_LOCAL ires NEVER use
475 * the ire_dep* pointers, so we'll use one (and independent of
476 * ip_stack_t's ips_ire_dep_lock as well). If I'm wrong,
477 * fix it here and add a new pointer in ip.h for ire_t.
478 */
479 ire->ire_dep_sib_next = (ire_t *)fixed;
480 VXNF_REFHOLD(fixed); /* ire holds us too... */
481 fixed->vxnf_ire = ire;
482 /* and then rewire the ire receive and send functions. */
483 if (ire->ire_ipversion == IPV4_VERSION) {
484 ire->ire_recvfn = vxlnat_fixed_ire_recv_v4;
485 ire->ire_sendfn = vxlnat_fixed_ire_send_v4;
486 } else {
487 ASSERT(ire->ire_ipversion == IPV6_VERSION);
488 ire->ire_recvfn = vxlnat_fixed_ire_recv_v6;
489 ire->ire_sendfn = vxlnat_fixed_ire_send_v6;
490 }
491 #if 1 /* Cheesy hack */
492 /*
493 * XXX KEBE SAYS CHEESY HACK:
494 */
495 if (!(ire->ire_ill->ill_flags & ILLF_ROUTER)) {
496 fixed->vxnf_clear_router = B_TRUE;
497 ire->ire_ill->ill_flags |= ILLF_ROUTER;
498 } else {
499 /* Just so we're clear... */
500 fixed->vxnf_clear_router = B_FALSE;
501 }
502 #endif /* Cheesy hack */
503 }
504 rw_exit(&vnet->vxnv_fixed_lock);
505
506 fail:
507 if (rc != 0)
508 vxlnat_public_rele(&vxnm->vxnm_public);
509
510 return (rc);
511 }
512
513 static void
514 vxlnat_rule_to_msg(vxn_msg_t *msg, vxlnat_rule_t *rule)
515 {
516 msg->vxnm_type = VXNM_RULE;
517 msg->vxnm_vnetid = VXLAN_ID_NTOH(rule->vxnr_vnet->vxnv_vnetid);
518 msg->vxnm_prefix = rule->vxnr_prefix;
519 msg->vxnm_vlanid = ntohs(rule->vxnr_vlanid);
520 bcopy(rule->vxnr_myether, msg->vxnm_ether_addr, ETHERADDRL);
521 msg->vxnm_public = rule->vxnr_pubaddr;
522 msg->vxnm_private = rule->vxnr_myaddr;
|