Using the Packet Filtering Hooks Interfaces

A substantial amount of
programming is required to work with the packet filtering hooks interfaces
because this API supports multiple instances of the IP stack running concurrently
in the same kernel. The IP stack allows multiple instances of itself for zones
and multiple instances of the framework support packet interception in IP.

This section demonstrates the set up code to use the packet filtering hooks
API to receive inbound IPv4 packets.

IP
Instances

The first decision
you need to make when you use this API is whether to accommodate multiple
instances of IP running in the kernel or to only interact with the global
zone.

To be aware of the presence of IP instances, register callback
functions that are activated when an instance is created, destroyed, and shut
down. Use net_instance_alloc() to allocate a net_instance_t packet event structure to store these three function pointers.
Use net_instance_free() to free resources when you no longer
need the callbacks and the structure. Specify nin_name to
give the structure instance a name. Specify at least the nin_create() and nin_destroy() callbacks. The nin_create() function
is called when a new instance of IP is created, and the nin_destroy() function
is called when an instance of IP is destroyed.

Specifying nin_shutdown() is optional unless the code will be exporting information to kstats.
To use kstats on a per-instance basis, use net_kstat_create() during
the create callback. Cleanup of the kstat information must happen during the
shutdown callback, not the destroy callback. Use net_kstat_delete() to
clean up kstat information.

If one or more instances of IP are present when net_instance_alloc() is called, the create callback will be called
for each currently active instance. The framework that supports the callbacks
ensures that only one of the create, destroy, or shutdown functions is active
at any one time for a given instance. The framework also ensures that once
the create callback has been called, the shutdown callback will only be called
after create has completed. Similarly, the destroy callback does not start
until the shutdown callback is complete.

The mycreate() function
in the following example is a simple example of a create callback. The mycreate() function records the network instance identifier in its
own private context structure and registers a new callback to be called when
a new protocol (such as IPv4 or IPv6) is registered with this framework.

If no zones are running (and therefore no instances other than the global
zone), calling net_instance_register() runs the create
callback for the global zone. You must supply the destroy callback so that net_instance_unregister() can be called later. Attempts to call net_instance_register() with either the nin_create or nin_destroy fields set to NULL will fail.

The function mynewproto() should
expect to be called each time a network protocol is either added to or removed
from a networking instance. If registered network protocols are already operating
within the given instance, then the create callback will be called for each
protocol that already exists.

Protocol Registration

For this callback,
only the proto argument is filled in by the caller. Neither
an event nor a hook name can be meaningfully supplied at this point. In this
example function, only events that announce the registration of the IPv4 protocol
are being looked for.

The next step in this function is to discover
when events are added to the IPv4 protocol by using the net_protocol_notify_register() interface to register the mynewevent() function.

The table below lists all three protocols that could
be expected to be seen with the mynewproto() callback.
New protocols could be added in the future, so you must safely fail (return
the value 0) any unknown protocols.

Programming Symbol

Protocol

NHF_INET

IPv4

NHF_INET6

IPv6

NHF_ARP

ARP

Event Registration

Just as the handling
of instances and protocols is dynamic, the handling of the events that live
under each protocol also is dynamic. Two types of events are supported by
this API: network interface events and packet events.

In the function
below, the announcement for the presence of the event for inbound packets
for IPv4 is being checked for. When that announcement is seen, a hook_t structure
is allocated, describing the function to be called for each inbound IPv4 packet.

The function mynewevent() will
be called for each event that is added and removed. The following events are
available.

Event Name

Data Structure

Comment

NH_PHYSICAL_IN

hook_pkt_event_t

This event is generated for every packet that arrives at the network
protocol and has been received from a network interface driver.

NH_PHYSICAL_OUT

hook_pkt_event_t

This event is generated for every packet prior to delivery to the network
interface driver for sending from the network protocol layer.

NH_FORWARDING

hook_pkt_event_t

This event is for all packets that have been received by the system
and will be sent out another network interface. This event happens after NH_PHYSICAL_IN
and before NH_PHYSICAL_OUT.

NH_LOOPBACK_IN

hook_pkt_event_t

This event is generated for packets that are received on the loopback
interface or that are received by a zone that is sharing its network instance
with the global zone.

NH_LOOPBACK_OUT

hook_pkt_event_t

This event is generated for packets that are sent on the loopback interface
or that are being sent by a zone that is sharing its network instance with
the global zone.

NH_NIC_EVENTS

hook_nic_event_t

This event is generated for specific changes of state for network interfaces.

For packet events, there is one specific event for each
particular point in the IP stack. This is to enable you to be selective about
exactly where in the flow of the packets you wish to intercept packets, without
being overburdened by examining every packet event that happens inside the
kernel. For network interface events the model is different, in part because
the events are much lower in volume and because it is more likely that the
developer will be interested in several of them, not just one.

The network interface event announces one of the following events:

An interface is created (NE_PLUMB) or destroyed (NE_UNPLUMB).

An interface changes state to up (NE_UP) or down (NE_DOWN).

An interface has an address change (NE_ADDRESS_CHANGE).

New network interface events could be added in the future,
so you must always return 0 for any unknown or unrecognized event that the
callback function receives.

The Packet Hook

The packet hook
function is called when a packet is received. In this case the function mypkthook() should expect to be called for each inbound packet that
arrives in the kernel from a physical network interface. Packets generated
internally, that flow between zones using the shared IP instance model or
over the loopback interface, will not be seen.

To illustrate the
difference between accepting a packet and allowing the function to return
normally with what is required to drop a packet, the code below prints out
the source and destination address of every 100th packet and then drops the
packet, introducing a packet loss of 1%.

Packets received by this function, and all others
that are called as a callback from a packet event, are received one at a time.
There is no chaining together of packets with this interface, so you should
expect only one packet per call and expect b_next to always
be NULL. While there is no other packet, a single packet may be comprised
of several mblk_t structures chained together with b_cont.