/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <inet/ipp_common.h>
/* Implementation file for classifier used in ipgpc module */
/*
* CHECK_MATCH_STATUS(match_status, slctrs_srchd, selector_mask)
*
* determines what the result of the selector search and what action needs to
* be taken next.
* if a NORMAL_MATCH occurs, business as usual NORMAL_MATCH
* if the selector was not searched because only DONTCARE keys are loaded,
* the selector is marked as not being searched
* otherwise, memory error occurred or no matches were found, classify()
* should return the error match status immediately
*/
(((match_status) == NORMAL_MATCH) ? \
(NORMAL_MATCH) : \
(((match_status) == DONTCARE_ONLY_MATCH) ? \
(match_status)))
/* used to determine if an action instance already exists */
/* Statics */
static void update_stats(int, uint_t);
/*
* common_classify(packet, fid_table, slctrs_srchd)
*
* searches each of the common selectors
* - will return NORMAL_MATCH on success. NO_MATCHES on error
*/
static int
{
int match_status;
/* Find on packet direction */
return (match_status);
}
/* Find on IF_INDEX of packet */
return (match_status);
}
/* Find on DS field */
return (match_status);
}
/* Find on UID of packet */
return (match_status);
}
/* Find on PROJID of packet */
return (match_status);
}
/* Find on IP Protocol field */
!= NORMAL_MATCH) {
return (match_status);
}
} else {
/* skip search */
}
/* Find on IP Source Port field */
!= NORMAL_MATCH) {
return (match_status);
}
} else {
/* skip search */
}
/* Find on IP Destination Port field */
!= NORMAL_MATCH) {
return (match_status);
}
} else {
/* skip search */
}
return (NORMAL_MATCH);
}
/*
* update_stats(class_id, nbytes)
*
* if ipgpc_gather_stats == TRUE
* updates the statistics for class pointed to be the input classid
* and the global ipgpc kstats
* updates the last time the class was matched with the current hrtime value,
* number of packets and number of bytes with nbytes
*/
static void
{
if (ipgpc_gather_stats) {
/* update global stats */
/* update per class stats */
gethrtime());
nbytes);
}
}
}
/*
* FREE_FID_TABLE(fid_table, p, q, i)
*
* searches fid_table for dynamically allocated memory and frees it
* p, q, i are temps
*/
/* free all allocated memory in fid_table */ \
for (i = 0; i < HASH_SIZE; ++i) { \
while (p != NULL) { \
q = p; \
p = p->next; \
kmem_cache_free(ht_match_cache, q); \
} \
} \
}
/*
* ipgpc_classify(af, packet)
*
* The function that drives the packet classification algorithm. Given a
* address family (either AF_INET or AF_INET6) the input packet structure
* is matched against all the selector structures. For each search of
* a selector structure, all matched filters are collected. Once all
* selectors are searched, the best match of all matched filters is
* determined. Finally, the class associated with the best matching filter
* is returned. If no filters were matched, the default class is returned.
* If a memory error occurred, NULL is returned.
*/
{
int match_status;
int class_id;
ht_match_t *p, *q;
int i;
int rc;
if (ipgpc_num_fltrs == 0) {
/* zero filters are loaded, return default class */
/*
* no need to free fid_table. Since zero selectors were
* searched and dynamic memory wasn't allocated.
*/
}
match_status = 0;
/* first search all address family independent selectors */
if (rc != NORMAL_MATCH) {
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
if (rc == NO_MATCHES) {
} else { /* memory error */
return (NULL);
}
}
switch (af) { /* switch off of address family */
case AF_INET:
/* Find on IPv4 Source Address field */
!= NORMAL_MATCH) {
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
if (match_status == NO_MATCHES) {
return (&ipgpc_cid_list[ipgpc_def_class_id].
aclass);
} else { /* memory error */
return (NULL);
}
}
/* Find on IPv4 Destination Address field */
!= NORMAL_MATCH) {
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
if (match_status == NO_MATCHES) {
return (&ipgpc_cid_list[ipgpc_def_class_id].
aclass);
} else { /* memory error */
return (NULL);
}
}
break;
case AF_INET6:
/* Find on IPv6 Source Address field */
!= NORMAL_MATCH) {
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
if (match_status == NO_MATCHES) {
return (&ipgpc_cid_list[ipgpc_def_class_id].
aclass);
} else { /* memory error */
return (NULL);
}
}
/* Find on IPv6 Destination Address field */
!= NORMAL_MATCH) {
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
if (match_status == NO_MATCHES) {
return (&ipgpc_cid_list[ipgpc_def_class_id].
aclass);
} else {
return (NULL);
}
}
break;
default:
ipgpc0dbg(("ipgpc_classify(): Unknown Address Family"));
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
return (NULL);
}
/* zero selectors were searched, return default */
if (slctrs_srchd == 0) {
/*
* no need to free fid_table. Since zero selectors were
* searched and dynamic memory wasn't allocated
*/
}
/* Perform best match search */
/* free all dynamic allocated memory */
FREE_FID_TABLE(fid_table, p, q, i);
}
/*
* bestmatch(fid_table, bestmask)
*
* determines the bestmatching filter in fid_table which matches the criteria
* described below and returns the class id
*/
static int
{
int i, key;
for (i = 0; i < HASH_SIZE; ++i) {
continue;
}
/*
* BESTMATCH is:
* 1. Matches in all selectors searched
* 2. highest priority of filters that meet 1.
* 3. best precedence of filters that meet 2
* with the same priority
*/
continue;
}
continue;
}
/*
* check to see if fid has been inserted into a
* selector structure we did not search
* if so, then this filter is not a valid match
* and bestmatch() should continue
* this statement will == 0
* - a selector has been searched and this filter
* either describes don't care or has inserted a
* value into this selector structure
* - a selector has not been searched and this filter
* has described don't care for this selector
*/
!= 0) {
continue;
}
/*
* tests to see if the map of selectors that
* were matched, equals the map of selectors
* structures this filter inserts into
*/
continue;
}
/* this filter becomes the bestmatch */
continue;
}
/*
* calculate the real priority by combining priority
* and precedence
*/
<< 32) |
/* check to see if this is the new bestmatch */
ipgpc3dbg(("bestmatch: filter %s " \
"REJECTED because of better priority %d" \
} else {
ipgpc3dbg(("bestmatch: filter %s " \
"REJECTED because of beter priority %d" \
}
}
}
ipgpc3dbg(("bestmatch: No filters ACCEPTED"));
return (ipgpc_def_class_id);
} else {
ipgpc3dbg(("bestmatch: filter %s ACCEPTED with priority %d " \
"and precedence %d",
}
}
/*
* get_port_info(packet, iph, af, mp)
*
* Gets the source and destination ports from the ULP header, if present.
* If this is a fragment, don't try to get the port information even if this
* is the first fragment. The reason being we won't have this information
* in subsequent fragments and may end up classifying the first fragment
* differently than others. This is not desired.
* For IPv6 packets, step through the extension headers, if present, in
* order to get to the ULP header.
*/
static void
{
if (u1) {
return;
}
} else { /* AF_INET6 */
switch (*nexthdrp) {
case IPPROTO_HOPOPTS:
return;
break;
case IPPROTO_DSTOPTS:
return;
break;
case IPPROTO_ROUTING:
return;
break;
case IPPROTO_FRAGMENT:
return;
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
/*
* Verify we have at least ICMP_MIN_TP_HDR_LEN
* bytes of the ULP's header to get the port
* info.
*/
ICMP_MIN_TP_HDR_LEN) > endptr) {
return;
}
/* Get the protocol and the ports */
return;
case IPPROTO_ICMPV6:
case IPPROTO_ENCAP:
case IPPROTO_IPV6:
case IPPROTO_ESP:
case IPPROTO_AH:
return;
case IPPROTO_NONE:
default:
return;
}
}
}
}
/*
* find_ids(packet, mp)
*
* attempt to discern the uid and projid of the originator of a packet by
* looking at the dblks making up the packet - yeuch!
*
* We do it by skipping any fragments with a credp of NULL (originated in
* kernel), taking the first value that isn't NULL to be the credp for the
* whole packet. We also suck the projid from the same fragment.
*/
static void
{
} else {
}
}
/*
* parse_packet(packet, mp)
*
* parses the given message block into a ipgpc_packet_t structure
*/
void
{
/* parse message block for IP header and ports */
}
}
/*
* parse_packet6(packet, mp)
*
* parses the message block into a ipgpc_packet_t structure for IPv6 traffic
*/
void
{
/* parse message block for IP header and ports */
/* Will be (re-)assigned in get_port_info */
/* Need to pullup everything. */
ipgpc0dbg(("parse_packet6(): pullup error, can't " \
"find ports"));
return;
}
}
}
#ifdef IPGPC_DEBUG
/*
* print_packet(af, packet)
*
* prints the contents of the packet structure for specified address family
*/
void
{
sizeof (saddrbuf));
sizeof (daddrbuf));
ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
", dport = %u, proto = %u, dsfield = %x, uid = %d," \
" if_index = %d, projid = %d, direction = %d", saddrbuf,
sizeof (saddrbuf));
sizeof (daddrbuf));
ipgpc4dbg(("print_packet: saddr = %s, daddr = %s, sport = %u" \
", dport = %u, proto = %u, dsfield = %x, uid = %d," \
" if_index = %d, projid = %d, direction = %d", saddrbuf,
}
}
#endif /* IPGPC_DEBUG */