WWDC2004 Session 102
Transcript
Kind: captions
Language: en
hello I'm here to talk about network
kernel extensions on tiger as you
probably already heard we've made a
number of massive changes to the
networking stack we had a few goals we
were we've got we needed to get better
SMP scalability we've been chipping
dual-processor machines for a long time
and the way that the locking model is
set up in the kernel in panther and
previous releases really didn't give us
an ability to take full advantage of
those multiple processors in addition we
wanted to add support for 64-bit
userspace processes and these changes
required in order to implement this we
needed to make a lot of changes to data
structures and moving up functions
around and it really led to just massive
changes almost everywhere which broke
kernel extensions the previous network
kernel extensions so if you have a
network crim o extension today that's
floating on Panther it won't load on
tiger if you use if you're just an IO
kit driver and ethernet driver or
something you'll be okay but if you've
been using the old dl IL layer or socket
filters protocol filters any of that
stuff you're going to need to make
changes to your nke to get it to work on
tiger some of these changes involves
moving to using opaque data structures
and XS or functions we provide colonel
programming interfaces which are
well-defined set of interfaces for
interacting with these data structures
and the stack the initial implementation
of those KPIs is available in the WWDC
build that's on your CD there are
actually some bugs in the kernel on that
that will lead to a panic in a few
situations so along with the previous
session session 103 there's some content
that's available online and part of that
is a new kernel that you can use when
you're trying to test these colonel
programming interfaces so I encourage
you to go ahead and download that and
install that there's a reading you that
explains how to get it installed and
that'll let you play around with what
I'm about to show you so we're going to
go over the colonel programming
interfaces
yeah these are available on tiger these
should give us more stability so that
when we make changes in the future we
aren't going to keep breaking your
kernel extensions and moving over to the
colonel programming interfaces is
required to get your text running on
tiger many of the symbols that use the
link against are no longer there so with
a better SMP scalability as I said we've
been shipping this dual processor
machines for a long time and we've been
using this thing called a funnel the
network funnel to protect all of the
data structures inside the kernel and
it's basically one big lock we've taken
that one big lock and we've moved to
finer grained locking where we use a
bunch of blocking primitives such as the
simple lock a mutex and multiple reader
single rider locks and we've really
broken it down so that we can have
multiple processors running through the
stack at the same time one of the
results of this is that the kernel
extensions are responsible for
protecting their own data since there's
no longer one big lock that goes the
stack and the kernel extensions are
running under they have to be aware that
they could be re-entered the internal
locking model that we use is mostly
transparent to the n que es and that was
done intentionally so that we will be
able to make changes to that in the
future as we tune the performance so in
Panther we have one big lock around
networking and we have another big lock
around the file system and in tiger so
the networking stack removed to a bunch
of smaller lock in various areas and
we're going to continue to fine-tune the
exact locking model and the KPIs are
intended to keep that transparent so
that you don't have to be involved with
it and we won't break you if we change
it we did change the data structures in
a lot of ways in order to implement this
adding locks to these structures and
moving stuff around adding reference
count his did affect the binary
compatibility we're going to have all
criminal private data structures be
opaque and we're going to provide
accessor functions so that in the future
when we need to make additional changes
to these it won't cause problems we
won't have to bake your text you won't
have to recompile you want it to deal
with any of that
there are five main network KPIs there's
the network interface KPI for providing
new interfaces to the networking stack
there's the socket KPI for interacting
with sockets in the stack and inside the
colonel this is commonly used for
network file system such as NFS AFP and
SMB we also have the socket filter KPI
for filtering data and connections at
the socket layer in addition is the IP
filter which lets you filter IP packets
at the IP layer regardless of the
interface and finally we have the
network interface filter which gives you
an ability to filter packets at the
interface layer there are a number of
additional help or KPIs for getting
access to various things such as I'm
buffs or communicating with a user Damon
in user space yeah so you have a diagram
of the networking stack here and at the
top layer we have the sockets the items
in blue can be provided by kernel
extensions so the kernel extensions can
interact with the socket they can create
a socket filter they can create an IP
filter they can create what we call
plumbers which I'll go into a little bit
later as well as interfaces and
interface filters so the network
interface layer it's actually broken up
into two different sections or two
different layers there's the interface
layer which has the interface itself
such as an ethernet interface or a PPP
interface and then there's the plumber
layer and the plumber is the glue
between a specific protocols such as IP
and an interface such as ethernet so
ideally the interface such as ethernet
would know nothing about the protocol
and the protocol shouldn't know anything
about the interface it's the plumbers
responsibility to tie these two things
together if you're familiar with the
datalink interface layer one of the
things we've done is eliminate the
interface family modules we found that a
lot of the functionality that was
provided by the interface family module
was already was usually tied to the
interface so we just went ahead and
rolled all that functionality into the
interface which makes it a lot easier to
provide a new interface because instead
of having to write an interface and an
interface family module you just do it
all in the interface we've also
eliminated DL tags
so when you're sending or receiving
you'll the package what used to be a dl
tag is now identified by both the
interface and the protocol family so at
the bottom of the stack we have network
interfaces and the network interface kpi
gives you the ability to provide new
interfaces to the networking stack a
network interface has five primary
responsibilities network interface is
responsible for inputting packets into
the stack as well as d muxing the
packets or determining which protocol a
specific packet belongs to as part of
the B MUX that has to handle add and
delete protocols so that it can keep
track of the D MUX descriptor mapping to
protocol family mapping so it can match
packets when they come in the interface
is also responsible for framing the
outbound packets basically putting an
interface header on it as well as
outputting the actual packet and
handling.i octal for things when for
cases where multicast filterless changes
or other state changes are requested the
network interface is documented in net /
KPI underscore interface by H in the
kernel framework network interfaces go
through a typical lifecycle the network
interface is allocated and then various
parameters and properties of that
interfacer set once the interface is set
up correctly the interface is attached
to the networking stack at that point
the protocols attached and then packets
are sent and received and then the the
interface can request a detach the
protocols detached from the interface
and then the interface itself is
detached from the stack for the
allocated interface there's a I F net
allocate function and you fill out an
if' net in its parameter a pram
structure that defines most of the
initial parameters of the interface part
of that is a unique ID and an interface
family right now the networking stack
keeps pointers to the network interface
all over the place and it doesn't
properly rest count rush count its
references to the interface so we can't
just get rid of the interface when your
interface goes away we end up recycling
it in the future we hope to get rid of
this but for now we're kind of stuck
with
there are some little gotchas though
with this when you're allocating an
interface and you specify a unique ID
and an interface family there must not
be another interface that's currently
attached with that unique ID and
interface family if there is an
interface and it's detaching then you
may block until that detach is completed
so that we can recycle to use the same
interface again the recycle mechanism is
temporary and we provide an if' net
reference and is net relief for handling
the reference counting for now when I
have net release reaches zero the
interface gets recycled in the future we
will free it after you've allocated the
interface you can set additional
properties once you've set up the
interface the way that you want it you
can use I F net attached to attach the
interface to the networking stack you
can also specify a link layer address
that will just be associated with that
interface at this point the interface
now appears in ifconfig and a kernel
event gets genesis generated to notify
the stack and people in user space or
processes in user space that a new
interface is attached and that made
sugar protocols to attach the protocol
touch is usually triggered from user
space in response to a kernel event that
an interface has been attached the
plumber code is responsible for handling
the attached it's plum function gets
called to attach the protocol to the
interface which in turn triggers the
interfaces add protocol function the
interfaces add protocol function gets
passed a list of lists of G MUX
descriptors and those DMX descriptors
then map to a specific protocol family
it's the interfaces responsibility to
keep track track of those mappings so
that when the demo Winnie interfaces d
MUX function gets called to match a
packet to a protocol it can refer to
that list that it's stored the protocol
detach is also handled by the plumber
the plumber unplumbed function is called
which then calls a function to detach
the protocol from the interface the
interface is the leak protocol function
gets called which gives the interface an
opportunity to clean up that d MUX
descriptor to protocol family mapping
once this is done the protocol detached
callback is called to notify the
protocol that it has been detached from
the interface the outbound packet passes
a little bit complex the protocol calls
is net output and the iaf net output
calls any interface filters pre output
functions and give the filters a chance
to process the packet the floor and
interface header has been prepended once
that's done the protocols pre output
function is called the protocols pre
output function is responsible for
determining the destination link layer
address this may require performing an
art or whatever neighborhood neighbor
discovery for ipv6 the protocols pre
output function is also responsible for
determining the frame type from there
the protocol at the destination link
layer address and the frame type are
passed on to the interfaces framer
function which then generates the
interface header at that point the
interface filters are all given an
opportunity to filter the fully formed
packet before the interfaces output
function is called to transmit the
packet on the inbound side the driver is
responsible for calling is net input to
pass the packet to the stack I have net
input cuse the packet and at a later
time the input thread comes along and
dq's the packet it then calls the
interfaces d MUX function to determine
which protocol that packet belongs to
the protocols interface filters have
been called and finally the protocols
input function is called to request a
detach from the sack the driver can call
is met detach the detaches are
asynchronous with a call back when you
call I've net detach there's a kernel
event that gets generated to notify the
stack and processes that the interface
is going away and this can lead to the
protocol this leads to the protocols
being detached once all the protocols
have been detached the interface is
removed from the list of interfaces and
the interfaces detached function is
called back to let the interface know
that it's safe to unload and that it
won't be called again
at this point to these stack releases
its reference on the interface and if
there are no other references the
interfaces either recycled if read there
are some locking considerations when
we're working with or supplying an
interface to the networking stack the
access to your network interface is not
serialized so you need to protect any of
your data structures there are also some
limitations in what you can do from your
callbacks you cannot add another
interface or add a protocol from any of
the callbacks that you supply through
the network interface in addition if
you're going to try and detach an
interface a protocol or an interface
filter these operations will be delayed
you do get some protection with the D
mocks your D max function will never be
called at the same time that either your
ad protocol or delete protocol functions
are being called in addition your ad
protocol function will never be called
at the same time as your delete protocol
function is called so if you're using a
linked list or something to keep track
track of the Emacs descriptor to
protocol family mappings you can
manipulate that list in your add and
delete protocol functions without
worrying about locking it moving up the
stack a little bit more we have the
protocol plumbers which are responsible
for gluing an interface to protocol and
these have the knowledge of how a
specific interface runs over a specific
specific protocol runs over specific
interface this is where knowledge of how
to perform our or neighbor discovery or
in the case of apple talk AARP would
live the protocol plumber registers a
plum and a nun plum function and the
plum function is responsible for
attaching the protocol and a nun plum
function is responsible for detaching
the protocol the protocol plumbers are
documented in net / KPI underscore
protocol that H in the kernel framework
the pump the plum function typically
calls is net attached protocol and it
specifies a list of democracy
descriptors which described in an
interface specific way the type of
packets that this protocol once
the plumber also specifies an input
function that will get called for any of
the packets that are received for this
protocol as well as a pre output
function an event function for handling
events on the interface and I octal for
handling any protocol specific event I
octaves on that interface and a detached
function to get notified when the
protocol has been detached the protocols
input function is important this is
where any art packets get handled or
something similar depending on which
protocol you're supporting in addition
if you need to strip any headers off or
do anything else so that you can just
pass a rob packet to the protocol you do
that in the plumber input function
before you call proto input proto input
is the function that you use to pass a
packet to a protocol once you've taken
anything out that's interface interface
specific the protocol plumbers pre
output function gets called on the
outbound path just before the framer
function for the interface and this
gives the protocol plumber an
opportunity to perform any arps the
protocol plumber is responsible for
determining the destination link layer
address and a frame type so that those
can be passed to the interface framer
function when you're working with the
protocol trump when you're working with
a protocol plumber there are a number of
locking considerations the unregister is
synchronous and the unregister won't
actually detach your protocols from
interfaces so you need to keep a count
of how many times you've attached if
you're supplying any function pointers
such as the input or pre output
functions because until you've been
detached from every interface your code
still going to get called and if you
unload before before you've been
detached you're going to lead you're
going to run into a panic there are some
restrictions and what you can do and
you're plumb and unplumbed functions you
really you must not try and register or
unregister another plumber and you also
cannot trigger a plumber unplumbed
function for any other protocols if you
do this you'll run into a deadlock
it's the top layer we have socket and
the socket KPI gives you access to
sockets inside of the colonel the KPI is
based on the user space api's and it
only lets you get access as a client of
the socket you can't implement a
protocol and interact with the socket in
the ways that a protocol would in place
of a struct socket pointer you now use a
socket t and user space of course you
use file descriptors but since this and
in the kernel since the layout of a
socket structure is private we're moving
to be opaque type socket t sockets go
through typical life cycle the socket is
created various options are set the
socket is connected data sent data is
received in the socket is close the
socket kpi is documented insist / kpi
socket H in the kernel framework so to
create a socket we use the function sock
socket and it's very similar to the
socket function in userspace it allows
you to discuss the major differences
that it allows you to specify an up call
function and the up call function will
let you get notification when data is
ready so in this example we're creating
a TCP socket and we're going to get back
the socket we're passing in my up calls
the up call function and my cookie is a
parameter that will get passed to the up
call function the sockets up call gets
called when either data is waiting to be
read or a connection is completed access
to your up call function is not
serialized so if you're going to be
manipulating data in your up call be
sure to take any lock the up call is
also called on the fastpass if you make
a blocking call in here you'll actually
stop all incoming data if you make a
blocking call in the socket in addition
if you do any processing that's going to
take a little while you should really do
it elsewhere because you're going to
hold up a lot of other stuff in this
case we have an up call function the
state's stored on the cookie and we
check to see if we're connected and then
we
former read after taking the lock which
should take a lock with a common set and
then we deal with some of the data and
then we would release the lock you can
use sock sock ops and sakai octal to set
various options there's also a sock get
saw cops to retrieve options in this
example we can see Sakai octos being
used to set the socket to non-blocking
i/o and the socks at sock opt is being
used to set the receive buffer size to
about 32 k there is no function that
you'd usually do use to make a file
descriptor non-blocking isn't available
in the colonel because you're not
working with a file descriptor here you
just have a raw socket so in order to
set non-blocking i/o you really need to
call sock I octal connecting a socket is
pretty straightforward sock connectors
based on the connect to userspace call
the difference between sock connect and
the old esso connect he's done any
programming and the colonel before with
socket is that sock connect will
actually block if the socket is a
blocking socket if you set the sockets a
non-blocking or you specify message
don't wait is the last parameter then
this will give you a non-blocking
connect you can use the function sock is
connected to determine whether or not
the socket has completed its connection
and you're up call will get called when
this connection completes with either
success or failure for sending there are
two different functions both of them are
based on sun message so they use a
message header socks friends will send
data that's stored in a kernel buffer
and socks & M buff will send data that's
stored in a chain of em buff in this
example we're filling out a message
header and we're setting the IO Beck to
the kernel buffer that we have and we
set up the name to point to the
destination that we want and then we
call sock send to send the data
receiving is much is very similar there
are two received functions and they're
based on received message so there's
Socrates and sock receive mbox sock
receives receives data into a colonel
offer and sock receive em buff receives
data into the received data is the M
buff in this example we're calling sock
receives and we're filling out our
message header first and we're
specifying a buffering the kernel and
when you're all done with the socket you
use sock close you can't call sock
clothes on a socket that's associated
with a file descriptor because that'll
really confuse the colonel since you
since the socialist API doesn't do
anything with the file descriptors
you're going behind the file descriptors
back there are some locking
considerations don't make calls the
sockets concurrently on different
threads while you're protected in
userspace through the file descriptor
layer if you do this in the colonel
we're not going through the file
descriptor layer so that protection is
pretty much gone and it especially if
you're reading on one socket and close
the socket on another socket you're
going to run into a kernel panic pretty
quickly in addition you're up call is
reentrant so be sure to protect data and
if you're going to do reads in two parts
be sure that you take a lock so that
somebody else can't if you do one little
read to get a header that tells you how
much data to read and you do another
read after that there's always a chance
that somebody might come in and do a
read between those two so be careful
about that so we have a socket filter
KPI that lets you filter data and
connections and other socket related
operations at the socket layer these are
commonly used for implementing a socket
layer firewall so you don't have to deal
with keeping track of all the state
yourself you can actually let the stack
do that you can also use it for
implementing privacy controls or content
filters as well as transparent proxies
and the socket filter KPI is documented
in this flash KPI underscore socket
filthy about H in the kernel framework
creating a socket filter is similar to
creating an interface you fill out a
structure that gives you the initial
values in this case it's an S FLT
underscore register structure and you
call SFL te underscore filter to
register the filter
the filter gets associated with a domain
a type and a protocol which are the same
ten parameters that are used for
creating a socket if you specify that
you want a global filter that global
filter will then be attached to any new
sockets that are created after you've
registered your filter and if you
specify a programmatic filter those
filters will be attached when somebody
uses the s.o nke socket option to
request your filter be attached to their
socket again you get you can be attached
in two different ways the global filters
are attached when the sockets are
created and the programmatic filters are
attached with the fon k socket option
when a socket is attached to when a
sucker filters attached to a socket the
attached function gets called and this
gives the socket filter an opportunity
to allocate some data for storing state
that will be associated with that
connection to that socket if you want to
you can return an error to prevent your
socket filter from being attached to the
socket to unregister and detach your
sockets you can call s FLT underscore
unregister and this is also an
asynchronous unregister with a call back
to let you know when it's completed when
you call this function it will prevent
any more sockets from being attached to
your socket filter and it will start
detaching your socket filter from all
the sockets that it's currently attached
to so your socket filter will get
detached when either the socket is
closed or the filter is unregistered the
SF unregistered callback that you can
specify indicates that the detaches then
complete and it's safe for you to unload
for filtering inbound data in the past
you had the filter or patch sb.append
that's the append a door sb.append
control it was kind of complicated and
convoluted there's just one inbound data
filter now called SF data and this
function is not called in the context of
the socket owners process so looking at
the clock info to get information is not
going to be useful from this function
you can modify the data in the unbuffed
chain the return value from this
function is very important if he returns
the data continues being processed as
normal if you return II just returned
the processing is going to stop and it's
going to assume that you've taken
responsibility for that data and that
data will not be freed if you return any
other error the processing will stop and
the data will be freed if you do
swallowed the data if by returning an
error or eat just returned the process
that owns the socket won't be woken up
if you need to inject data later you can
use the sock inject data in function for
outbound data it's much the same there's
an SF data out call back you can specify
this is usually called in the context of
the socket owners process the data can
be modified and the return values are
just the same for data out if you return
to 0 then it processes as normal if your
turn II just returned then your the
processing stops and you're free to hold
on to that data if you return any other
value the processing stops and the data
gets freed if you need to later inject
some data that you would cute or
something you can use sock inject data
out you can also filter binds this lets
you either bind to a different address
from the requested one or prevent the
bind all together if you need to bind to
a different address call sock bind again
on the same socket but with the new
address that you want to bind to and
then return Aegis return or if you got
an error back from your second call to
sock find you need to return that error
if you do intercept the bind and bind to
a different address you may want to also
intercept the get sock main so that you
can keep the process thinking that it
connected to the fact that it found to
the socket that it tried to bind to you
can also filter connects both inbound
and outbound for inbound connects you
can only allow them or disallow them you
can't change the address that the
connection is coming in from for the
outbound connections you can allow or
disallow and you can also connect to a
different address if you need to connect
to a different address call stock
connect again and specify the new
address and then return e just return
it's not connect succeeded if sock
connect failed then go ahead and return
the error that you got some socks
and again you can intercept get pure
name to keep the process thinking that
it connected to the address that it had
requested there's some additional
filtered points for sockets the SF
notify notifies you of socket state
changes for example when you're being
disconnected or you're in the
disconnecting state you can also
intercept socket options using the SF
sets option and SF get option callbacks
you can intercept I octal you can either
handle them or block them you can also
intercept listen to prevent processors
from being able to create listening
sockets so moving down the stack a
little bit more we have IP filters IP
filters give you a chance to filter
packets at the IP layer and the really
nice thing about IP filters is that
they're the packets are passed to you
after they've been reassembled on the
inbound side so you don't have to deal
with fragments on the outbound side you
get the packets before they've been
fragmented and the filter is also
interface independent so you don't have
to worry about attaching a different
filter to every single interface that
comes up and has IP attached to it you
also get an opportunity to process the
packets both before and after IPSec the
IP filters go through a typical life
cycle they're attached to either ipv4 or
ipv6 and then they filter inbound and
outbound data and then they're detached
they're documented in that I net / KPI
underscore IP filter H in the kernel
framework the IP filters are attached
using ipf add before an IPF add v6 and
they both use the same structure to
define a input and output filter
function calling these functions returns
a filter rep that you use for later
detaching the filter the IPF input
function is called for input for inbound
packets and this is called after the
pack has been reassembled and both
before and after IPSec processing the
output function is just the same but
it's called
excuse me called before we fragments a
packet but also before and after we
doing the IPSec processing so the
function gets called and it's passed in
the protocol and the protocol is
specifies the protocol that we're
currently processing at and you also get
an offset from the beginning of the
packet to that protocol so the beginning
of the n buff chain will always start at
the IP header or ipv6 header and then
for an IPSec process you'll get called
for an IPSec packet you might get called
one with the ESP header with the offset
from the IP packet to the ESP header and
once IPSec is decrypted the packet
you'll get called again with beyond with
TCP or ICMP and the offset from the IP
header to the ICMP header you can use
IPS inject input and ipf inject outputs
to inject data with ipf inject input it
injects the data right after the packets
have been reassembled in IP input if you
pass a filter ref it will prevent this
packet from getting processed again by
both your filter and any filters before
you if you've modified the packet you
shouldn't pass a filter rest because
that will prevent any of filters from
having a chance to look at the new
modified packet ipf inject output inject
the data right into the IP output
function and again you can pass a filter
ref to avoid processing the packets
twice to detach your filter you call ipf
remove this detach is asynchronous and
your ipf detach callback will get called
to notify you when your filter has been
detached and it's safe to unload there
are some considerations with locking
again access to your IP filter is not
serialized so you need to be sure and
protect any data structures that you've
got in addition if you're going to call
in a call to inject data you need to
drop the locks before performing the
inject because there's a chance that you
might get called reentrant lee and if
you try and take your lock again then
you end up with a deadlock this is
broken in the WWDC build you'll need to
is the colonel that comes as part of the
session 103 supplemental stuff moving
down to the bottom of the stack we have
the interface filters the interface
filters let you filter inbound and
outbound packet at the interface layer
you can also filter the I octal
interface filters are commonly used for
a packet latest firewall or something
like a virtual packet switch the
interface filters are all also the
replacements for the old protocol filter
we no longer have protocol filters the
interface filters are documented in net
/ KPI underscore interface filtered H in
the kernel framework to attach an
interface filter you fill out an iff
filter structure and then you call I FLT
attached this gives you an opportunity
to specify a protocol it's important to
note that the protocol doesn't specify
you you aren't attached to that protocol
attachment with the old protocol filters
if you want to attach to IP / am0 you
could only do that when i pea was
attached to en 0 with the new interface
filters you can specify that you want to
get IP packets and you can attach the en
0 even when i pea isn't attached and
your filter will remain attached until
the interface goes away or until you
detach it you just won't receive any
packets unless I p is actually attached
when you're ready to detach your filter
you call I FLT underscore detach and
this is asynchronous with a call back to
let you know when it's safe to unload
for filtering inbound packets the
interfaces d MUX function gets called
first to give it an opportunity to match
the packet to a protocol so that we can
know which interface filters to pass
this to if you specify 0 for the
protocol then you get all packets for
any protocol or packets that don't match
any protocol that's currently attached
your iff input function will get called
it's allowed to modify the packet if it
does need to modify
packet it should verify that the check
sums are correct it's going to make any
changes that affect the checksum and it
should call em buff inbound modified and
this will clear all the checksum flags
so that we don't try and perform a
hardware checks on later and run into
problems the return values are important
like in the socket filter if you return
a 0 then the processing continues as
normal if your turn II just returns the
processing stops but the packets not
freed to be responsible for either
queuing it and rejecting it later or
freeing it or doing whatever you want
with it but you're responsible for
freeing it he returned any other value
it'll end up freeing the packet and the
processing will stop on the outbound
side you have two different places that
you can filter there's a pre output
function that lets you handle the packet
before the interfaces framer has had a
chance to pretend be interface header on
the outbound you also have the ifs
output function which gives you a chance
to process the fully formed packet which
includes the interface header if you're
going to modify the packet you should
call em buff outbound finalize which
will force it to do any check sums and
software that would have been done in
hardware so you get a fully formed
packet and it also clears all the checks
on flag so if you reject it somewhere
else you don't run into problems this
may perform additional work such as
inserting a deal and header although
those packets probably won't get past
your filter the return value is
important and it's just like the return
values for the socket filter and the
inbound filter if you return 0 then
processing continues as normal if your
attorney just returned then you get to
hold on to the packet if you return any
error values in the packet gets free to
the processing stop there are some
additional places additional filters
stuff you can set up at the interface
layer the ISS event lets you receive
notifications of events on the filter on
the interface most common events are
protocols attaching and detaching and
the interface detach
the iffi octal lets you filter the I
Ospital functions so you can either
intercept and handle your own I octal or
you can intercept cocktails that would
normally go to the interface if you need
to inject inbound or outbound data you
can use the if' net input function and i
have met output functions if you need to
communicate with a user space process
the easiest way to do that is to use the
colonel control KPI colonel control
gives you a way to send small messages
over a socket to user space it's
commonly used for configuring a kernel
extension or for retrieving information
from a kernel extension the colonel
control KPI is documented insist flash
current control H in the kernel
framework registering your kernel frame
sorry registering your kernel control is
done by filling out a current control
register struck and calling control
register this lets your kernel extension
receive notification when a socket
connects to your kernel control or when
it disconnects it also lets you receive
information from user land and you can
get you can handle get and set socket
options when you're done you can call
control be register and that will
unregister your control
so when your control connect function
gets called you can allocate any data
that you need to associate with that
connection to a specific socket and then
you need to free that on your control
disconnect call back if you need to send
data to this to the process into the
socket you can use ctrl + Q data and
control and QM bus control and Q data
works with a kernel kernel buffer and
ctrl + qm buff works with data that's
stored in an M buff chain with the
colonel control access to it is not
serialized but it is safe to send to the
client at any time so the with the
nothing see realized you really need to
protect any data structures that you
interact with whenever you get a call
back to notify users data on the socket
in addition is a another helper KPI the
protocol layer and this is documented in
net / KPI underscore protocol that H in
the kernel framework this applies to you
the hooks for injecting packets into a
protocol there are two functions of the
proto input function and the proto
inject function the proto input function
is intended for plumbers for passing
packets up to IP or ipv6 or even Apple
talk and they're really meant for the
inbound packet path if you're going to
be injecting packets from anywhere else
in the stack where you're not on the
inbound pass you need to use the proto
inject function and these are the
replacement for the net is are
mechanisms that used to cue packets and
then wake up the input thread in
addition there's an M buff kpi that
gives you access to the data that's
stored in EM bus most of the packets all
of the packets in the stack restored in
n buff along with a bunch of other
useful information the n buff kpi is
based on the original n buff interfaces
and we've added a lot of accessories the
accessor functions names are based on
the field name in the old n buff so for
example n buff underscore lengths gets
the length of the Amba the headers in
the M buffs have changed a little bit
and the result of those changes may be
that
you can't sort quite as much data in the
namm buff that has a packet header or
even a regular n buff and the cluster
sizes might also change so don't make
any assumptions about the amount of data
that you can store in an n buff you can
use em buff stat to get the values of
all of the sizes for the various m buffs
with headers and clusters we may be
changing these things again we change
them in Tiger to add support for and
buff tags the M buff KPI is documented
in this flash KPI underscore n buff eh
there's still a number of things that
are missing and we're working to get
these in there as quickly as we can
there's no access to the routing tables
which makes it a little bit difficult
for the plumbers to perform their our
code correctly there's also no access to
BPS but we will be providing access for
tiger there are no accessories for
indicating that you support hardware
checksums or for detecting that a packet
requires or request some hardware
checksum there are the two functions for
clearing those flags on both the inbound
and outbound side there isn't a whole
lot of sample code but we're working to
change that in addition the colonel
framework hasn't been completely cleaned
up yet for Tiger GM we're hoping to get
the colonel framework clean so that
there aren't any data structures or
functions in that framework that aren't
part of the KPI in addition the list of
exported symbols to the BFC colonel text
hasn't been cleaned up yet so that there
are still some symbols in there that we
don't want to have as part of the KPI
but for Tiger GM we will clean that up
in addition we really need your feedback
we have an email address set up kpi
feedback at apple com and we need you to
get started soon because the earlier
that you give us feedback but easier
it's going to be for us to get the
changes that you need into the kernel so
that you can get your network criminal
extension working on tiger
there are some resources for more
information Craig Keithley is the IO
technology invent evangelist and there's
the KPI feedback email address kpi dash
feedback and apple com in addition we
have the some more reference stuff the
NK the network colonel extension KPI
reference is available online and also
in the developer folder that gets
installed with Tiger there's some more
reference