2 \documentclass{article}
6 \noweboptions{smallcode,hideunuseddefs}
10 \def\nwendcode{\endtrivlist\endgroup}
13 \title{ Interface Tools\thanks{
14 Copyright \copyright\ 1999--2005 Anthony Towns. This program is free
15 software; you can redistribute it and/or modify it under the terms of
16 the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any
21 \author{ Anthony Towns \\ { \tt aj@azure.humbug.org.au } }
30 \pagenumbering{arabic}
32 \section{Introduction}
34 This source defines the commands [[ifup]] and [[ifdown]], used to
35 manipulate interfaces in an easily controllable manner.
37 \subsection{Assumed Knowledge}
39 The reader is assumed to have knowledge of the C \cite{K&R} and Perl
40 \cite{camel} programming languages in a Unix environment \cite{StevensUnix}.
41 A cursory understanding of network administration on the appropriate
42 platform is also assumed, along with access to the relevant manual
45 This source has been written as a literate program using the [[noweb]]
46 \cite{wwwnoweb} tool suite, and typeset using \LaTeX\ \cite{latex}.
48 \subsection{Program Structure}
50 We shall decompose this program into four main areas of functionality:
51 compile-time configuration, run-time configuration, execution, and the
54 Compile-time configuration will deal with differing available address
55 families (IP vs IPX vs IPv6, and so on), and the differing methods of
56 enabling and disabling interfaces configured for each family. This will
57 be implemented using the [[addrfam]] module, and various [[.defn]] files,
58 for the address family definitions.
60 Run-time configuration will deal with determining the local setup
61 based on the file [[/etc/network/interfaces]], and producing a data
62 structure encapsulating these details. This will be implemented in the
65 Execution will deal with issues relating to working out exactly which
66 commands to run based on a somewhat abstract description from the
67 compile-time configuration and the details determined at
68 run-time. This will be dealt with in the [[execute]] module.
70 The remaining work --- argument parsing, error reporting, and,
71 essentially, putting all the pieces together --- is done by the
74 The following diagram gives a brief idea of the information and control
75 flow amongst the modules.
78 \includegraphics[height=45mm]{modules}
81 Much of the information sharing will be done by defining and filling
82 in some data structures and allowing the other modules to just access
83 that information directly. Rather than hiding the information itself,
84 most of our modules simply attempt to hide how that information was
85 originally written. Because of this, we shall find that these modules are
86 too closely linked to be completely separated in a convenient manner,
87 so they will all make use of a single header file for each other's
88 structure definitions, exported interfaces and so on.
95 <<function type definitions>>
96 <<structure definitions>>
97 <<constant definitions>>
100 #endif /* HEADER_H */
103 \section{The Build System}
105 We shall begin with the template for the Makefile we shall use.
110 CFILES := addrfam.c execute.c config.c main.c archlinux.c
111 HFILES := header.h archlinux.h
112 PERLFILES := defn2c.pl defn2man.pl
113 DEFNFILES := inet.defn ipx.defn inet6.defn
115 OBJ := main.o addrfam.o execute.o config.o \
116 $(patsubst %.defn,%.o,$(DEFNFILES)) archlinux.o
118 MAN := $(patsubst %.defn,%.man,$(DEFNFILES))
120 default : executables
121 all : executables docs
123 executables : ifup ifdown ifup.8 ifdown.8 interfaces.5
124 docs : ifupdown.ps.gz ifup.8.ps.gz interfaces.5.ps.gz ifupdown.pdf
128 <<executable targets>>
130 <<extra dependencies>>
133 <<generated dependency inclusion>>
136 We shall build exactly two executables, [[ifup]] and [[ifdown]], which
137 will in truth simply be two names for a single binary, albeit with
138 different functionality.
140 <<executable targets>>=
142 $(CC) $(CFLAGS) $^ $(LDFLAGS) $(OUTPUT_OPTION)
148 Both of these executables have a manpage. Since they're actually the
149 same executable, what could be more appropriate than them having the
153 interfaces.5: interfaces.5.pre $(MAN)
154 sed $(foreach man,$(MAN),-e '/^##ADDRESSFAM##$$/r $(man)') \
155 -e '/^##ADDRESSFAM##$$/d' < $< > $@
161 groff -mandoc -Tps $< > $@
163 groff -mandoc -Tps $< > $@
166 Further, for convenience, we'll make use of two phony targets, [[clean]],
167 [[clobber]] and [[distclean]], which will delete working files, everything
168 that can be rebuilt with a [[make]] command, and everything that can be
169 rebuilt at all, respectively.
172 .PHONY : clean clobber
175 install -m 0755 -d ${BASEDIR}/sbin
176 install -m 0755 ifup ${BASEDIR}/sbin
177 ln ${BASEDIR}/sbin/ifup ${BASEDIR}/sbin/ifdown
180 rm -f *.aux *.toc *.log *.bbl *.blg *.ps *.eps *.pdf
181 rm -f *.o *.d $(patsubst %.defn,%.c,$(DEFNFILES)) *~
182 rm -f $(patsubst %.defn,%.man,$(DEFNFILES))
183 rm -f ifup ifdown interfaces.5 ifdown.8
184 rm -f ifupdown.dvi *.ps{,.gz}
187 rm -f ifupdown.tex $(PERLFILES) $(CFILES) $(HFILES) $(DEFNFILES)
190 rm -f makecdep.sh makenwdep.sh Makefile
193 We have some fairly standard rules to build the printed version of the
194 source code using \LaTeX\ that are, unfortunately, not included in
195 [[make(1)]]'s builtin rules, so we'll note them here.
199 noweave -delay -index -latex $< >$@
201 %.bbl : %.tex biblio.bib
203 bibtex $(basename $<)
217 gzip --best --stdout $< >$@
220 Additionally, some of [[make]]'s builtin rules are fairly
221 conservative, so we'll encourage it to use a more entertaining method
222 of compiling source code.
225 CFLAGS := -Wall -W -g -O2 -D'IFUPDOWN_VERSION="0.6.5"'
229 \subsection{Graphics}
231 We include a few graphics (made using dia) in this document. We have to
232 express these fairly explicitly, unfortunately.
236 dia --nosplash -e $@ $<
239 gs -q -sDEVICE=pdfwrite -dNOPAUSE -sOutputFile=$@ - < $<
242 <<extra dependencies>>=
243 ifupdown.dvi: modules.eps execution.eps
244 ifupdown.ps: modules.eps execution.eps
245 ifupdown.pdf: modules.pdf execution.pdf
248 \subsection{Automatic Dependencies}
250 To build the system, we'll make use of some techniques discussed in
251 \cite{recursivemake} for determining dependencies. Namely, a number
252 of files will have an associated [[.d]] file containing dynamically
253 determined dependency information. The first such file we will construct
254 is the dependency information for [[noweb]] source files, which can be
255 identified by the [[.nw]] extension.
258 %.d: %.nw makenwdep.sh
259 ./makenwdep.sh $< > $@
262 To construct the dependency information, we may use the [[noroots(1)]]
263 command to determine the \emph{root chunks} in the [[noweb]] source
264 (stripping the unwanted [[<<]] and [[>>]] markers as we go, and
265 denoting that in such a way that [[noweb]] doesn't mistakenly think
266 the [[sed]] command is a chunk reference itself), and then noting down
267 appropriate commands to construct the target.
270 <<parse makenwdep arguments>>
272 noroots $FILE | sed 's/^<''<\(.*\)>>$/\1/' |
274 <<output dependency info for [[$chunk]]>>
278 Our dependency information is straightforward. To construct a file from
279 [[noweb]] source, we simply need to run [[notangle(1)]] over it. We add
280 a couple of extra tweaks in order to only update files that were actually
281 changed (the [[cpif(1)]] call), and to handle tabs properly.
283 We also need some extra things to take care of particular types of files.
284 In particular its important to have our scripts marked executable, so we
285 can use them as part of the build process itself, and it's also important
286 to have the dependency information for our C files (which are dealt with
287 next) included at some point.
289 <<output dependency info for [[$chunk]]>>=
290 printf "%s : %s\n" "$chunk" "$FILE"
293 printf "\tnotangle -R\$@ \$< >\$@\n"
294 printf "\tchmod 755 %s\n" "$chunk"
297 printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
298 printf "include ${chunk%.c}.d\n"
301 printf "\tnotangle -L -R\$@ \$< | cpif \$@\n"
304 printf "\tnotangle -t8 -R\$@ $< >\$@\n"
309 Finally, our fairly primitive argument parsing is simply:
311 <<parse makenwdep arguments>>=
314 if [ "$FILE" = "" -o ! -f "$FILE" ]; then
315 echo "Please specify a .nw file"
320 We have a related system for object files generated from C source
321 code. Since each object file depends not only on its source, but also
322 the headers included in that source, we generate a [[.d]] file indicating
323 exactly which headers need to be checked.
327 ./makecdep.sh $< > $@
330 We can do this using [[gcc(1)]]'s convenient [[-MM -MG]] options,
331 which do exactly this, with the added proviso that the [[.d]] file
332 itself can possibly depend on any of the header files being modified
333 (and, in particular, [[#include]] lines being added or deleted).
337 <<parse makecdep arguments>>
340 sed -e 's@^\(.*\)\.o:@\1.o \1.d:@'
343 \emph{Deja vu}, anyone?
345 <<parse makecdep arguments>>=
347 if [ "$FILE" = "" -o ! -f "$FILE" ]; then
348 echo "Please specify a .c file"
353 To include the generated dependencies in [[Makefile]], we have to
354 be a bit careful. The problem here is that they should not be rebuild
355 when merely the cleaning of the source tree is asked for. Any targets
356 ending in [[clean]], plus the [[clobber]] target prevent the inclusion
357 of the generated dependencies.
359 Unfortunately, [[make]] doesn't allow logical combinations within
360 [[ifeq]] and friends, so we have to simulate this.
362 <<generated dependency inclusion>>=
364 ifneq "" "$(filter %clean,$(MAKECMDGOALS))"
367 ifeq "clobber" "$(MAKECMDGOALS)"
372 Finally, include the dependency information:
374 <<generated dependency inclusion>>=
375 ifeq "$(strip $(include-deps))" "YES"
380 \section{Compile Time Configuration}
382 At compile time we need to determine all the possible address families
383 that may be used, and all the methods of setting up interfaces for
384 those address families, along with the various possible options
385 affecting each method.
387 Our key definition at this point is that of the [[address_family]]
388 structure, which encapsulates all the compile time information about
391 <<type definitions>>=
392 typedef struct address_family address_family;
395 <<structure definitions>>=
396 struct address_family {
403 Each defined address family will be included in the [[addr_fams]]
404 array, which becomes the \emph{raison d'\^etre} of the [[addrfam]]
407 <<exported symbols>>=
408 extern address_family *addr_fams[];
411 Each address family incorporates a number of methods, which
412 encapsulate various ways of configuring an interface for a particular
413 address family. There are two definining components of a method: two
414 sets of commands to bring an interface up and down, and a number of
415 options for the commands.
417 \emph{NB: I expect this will be extended sooner or later to make the
418 options more flexible. Probably introducing some form of typing (for
419 example to convert netmasks from CIDR specs to dotted-quads, ie
420 /24~$\rightarrow$~255.255.255.0), and some form of matching to allow
421 multiple options to be deduced from a single configuration
424 <<type definitions>>=
425 typedef struct method method;
428 <<structure definitions>>=
431 command_set *up, *down;
435 Each command set is implemented as a single function, accepting two
436 parameters: the definitions of the interface the commands should deal
437 with, and the function that should be used to execute them. See the
438 [[execute]] module for more details.
440 <<function type definitions>>=
441 typedef int (execfn)(char *command);
442 typedef int (command_set)(interface_defn *ifd, execfn *e);
445 As our compile-time configuration is done at, well, compile-time, there
446 is little need for functions in the actual module, and we can make do with
447 a single exported array.
453 <<address family declarations>>
455 address_family *addr_fams[] = {
456 <<address family references>>
461 \subsection{Generating C Code}
463 Unfortunately, while the [[.defn]] representation is reasonably
464 convenient for human use, it's less convenient for a compiler. As
465 such, at build time, we will build a single structure of type
466 [[address_family]] in a separate module, and reference that from
469 Naturally, we'll use a [[perl]] script to convert [[.defn]] files to C
473 %.c : %.defn defn2c.pl
477 The functionality of our program is pretty basic: read from the file
478 specified as the argument, output to [[stdout]]; and correspondingly
479 the structure of the program is similarly simple. We make use of a
480 couple of global variables, a few helpful subroutines, and then build
492 <<defn2c subroutines>>
495 <<output headers for address family>>
496 <<parse [[.defn]] file and output intermediate structures>>
497 <<output address family data structure>>
500 Clearly we need to reference some of the data structures we defined
501 above, so we can begin with the rather trivial:
503 <<output headers for address family>>=
504 print "#include \"header.h\"\n\n\n";
507 The overall purpose of the C code we're trying to construct is to
508 define a structure of type [[address_family]], and have it externally
509 visible. So we'd like to declare a statically-initialized structure of
510 this type, and be done with it.
512 To do this, however, we need to have some way of uniquely identifying
513 the structure to avoid naming conflicts. We'll do this by assuming we
514 have a previously initialized variable, [[$address_family]], and that
515 names of the form [[addr_foo]] won't be used elsewhere.
517 <<defn2c variables>>=
518 my $address_family = "";
521 We also need to reference an array of pointers to this address
522 family's [[method]]s, which will have to be initialized separately.
523 We'll assume that previous code will create such a structure, and call
524 it (imaginatively) [[methods]].
526 <<output address family data structure>>=
527 <<output [[methods]] data structure>>
530 address_family addr_${address_family} = {
532 sizeof(methods)/sizeof(struct method),
538 Our [[methods]] array will be a little more complicated to
539 construct. The first difficulty is that it will actually require some
540 state from having read the [[.defn]] file. To handle this, we'll
541 introduce a hash [[%methods]] that has the value [[1]] for each method
542 from the [[.defn]] file. We use a hash instead of a list because it
543 makes some error checking more convenient later, and since order
544 doesn't particularly matter.
546 <<defn2c variables>>=
550 We'll use standard names, such as [[foo_up]], [[foo_down]], and
551 [[foo_options]] for the various elements of each method which cannot
552 be defined inline. The two functions and the array will be declared
553 static to avoid name conflicts.
555 <<output [[methods]] data structure>>=
556 print "static method methods[] = {\n";
558 foreach $method (keys %methods) {
562 ${method}_up, ${method}_down,
569 In a reasonably obvious manner we can then proceed to process the
570 [[.defn]] file to initialize the aforementioned variables, and to
571 output the method-specific functions and array. We'll begin by
572 defining a variable to keep track of the current line.
574 <<defn2c variables>>=
578 Our semantics for this variable will be basically that it contains a
579 valid, meaningful input line. It won't be blank, or contain comments,
580 and if there aren't any more lines to be read, it will evaluate to
581 [[false]]. In order to keep these semantics, we'll use the subroutine
582 [[nextline]] to update it. (Since we'll later find we'll want to reuse
583 this subroutine, we'll keep it in a chunk of its own)
585 <<defn2c subroutines>>=
586 <<[[nextline]] subroutine>>
589 <<[[nextline]] subroutine>>=
592 while($line and ($line =~ /^#/ or $line =~ /^\s*$/)) {
595 if (!$line) { return 0; }
597 while ($line =~ m/^(.*)\\$/) {
606 Our high-level logic then looks basically like:
608 <<parse [[.defn]] file and output intermediate structures>>=
611 <<parse a top-level section and output intermediate structures>>
614 die("Unknown command \"$line\"");
618 To make all this stuff easier, we'll use a `matching' function to help
619 with parsing lines: basically, given a line, a command, and possibly
620 an indentation prefix (eg [[" "]]). (As with [[nextline]], this will
621 also be useful to reuse, hence it has its own pair of chunks, too)
623 <<defn2c variables>>=
627 <<defn2c subroutines>>=
628 <<[[match]] subroutine>>
631 <<[[match]] subroutine>>=
634 my $cmd = "$_[1]" ? "$_[1]\\b\\s*" : "";;
635 my $indentexp = (@_ == 3) ? "$_[2]\\s+" : "";
637 if ($line =~ /^${indentexp}${cmd}(([^\s](.*[^\s])?)?)\s*$/) {
646 Okay. So, the first line we expect to see is the name of the address
647 family we're defining.
649 <<parse a top-level section and output intermediate structures>>=
650 if (match($line, "address_family")) {
651 get_address_family $match;
656 This is, as you'd imagine, pretty simple to deal with. We just need to
657 store the address family's name, and move on to the next line.
659 <<defn2c subroutines>>=
660 sub get_address_family {
661 $address_family = $_[0] if ($address_family eq "");
666 Which brings us to determining the architecture.
668 <<parse a top-level section and output intermediate structures>>=
669 if (match($line, "architecture")) {
670 get_architecture $match;
675 You'd never guess what, but it's just as easy as the address family thing
678 <<defn2c subroutines>>=
679 sub get_architecture {
681 die("architecture declaration appears too late") if (keys %methods);
682 print "#include \"arch${arch}.h\"\n\n\n";
687 Which leaves us with the hard bit, actually creating the functions and
688 array for each method.
690 <<parse a top-level section and output intermediate structures>>=
691 if (match($line, "method")) {
697 The basic premise is to check for each of our options in a given
698 order: if they don't match, then we can presume they don't exist ---
699 any errors will be reported when the main function finds something
700 weird going on. All we really have to take care of so far is ensuring
701 an appropriate level of indentation, and that we're not defining the
704 <<defn2c subroutines>>=
707 my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
709 die "Duplicate method $method\n" if ($methods{$method}++);
712 <<output code for description>>
713 <<output code for options list>>
714 <<output code for up commands>>
715 <<output code for down commands>>
719 The description and options sections are just documentation chunks,
720 and hence aren't at all relevant for the C code.
722 <<output code for description>>=
723 if (match($line, "description", $indent)) {
728 <<output code for options list>>=
729 if (match($line, "options", $indent)) {
734 Skipping a section is fairly easy: we just need to check alignments. This is
735 yet another subroutine that'll come in handy elsewhere.
737 <<defn2c subroutines>>=
738 <<[[skip_section]] subroutine>>
741 <<[[skip_section]] subroutine>>=
744 my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
746 1 while (nextline && match($line, "", $indent));
750 Checking the various relevant components of each method is fairly
751 simple: we need to see if it exists, and if it does, parse and output
752 it, while if it doesn't, we need to output a place holder.
754 <<output code for up commands>>=
755 if (match($line, "up", $indent)) {
756 get_commands(${method}, "up");
758 print "static int ${method}_up(interface_defn ifd) { return 0; }\n"
762 <<output code for down commands>>=
763 if (match($line, "down", $indent)) {
764 get_commands(${method}, "down");
766 print "static int ${method}_down(interface_defn ifd) { return 0; }\n"
770 <<defn2c subroutines>>=
774 my $function = "${method}_${mode}";
775 my $indent = ($line =~ /(\s*)[^\s]/) ? $1 : "";
777 print "static int ${function}(interface_defn *ifd, execfn *exec) {\n";
779 while (nextline && match($line, "", $indent)) {
780 if ( $match =~ /^(.*[^\s])\s+if\s*\((.*)\)\s*$/ ) {
781 print "if ( $2 ) {\n";
782 print " if (!execute(\"$1\", ifd, exec)) return 0;\n";
784 } elsif ( $match =~ /^(.*[^\s])\s+elsif\s*\((.*)\)\s*$/ ) {
785 print "else if ( $2 ) {\n";
786 print " if (!execute(\"$1\", ifd, exec)) return 0;\n";
788 } elsif ( $match =~ /^(.*[^\s])\s*$/ ) {
790 print " if (!execute(\"$1\", ifd, exec)) return 0;\n";
800 \subsection{Building Manual Pages}
802 So having C code is all very well, but if you want to ignore all user
803 problems with a casual ``RTFM!'' there has to be some semblance of an
804 M for them to R. So we need a script to generate some useful
805 descriptions of the various methods.
807 We'll achieve this by making another Perl script, [[defn2man.pl]],
808 which will generate fragments of [[troff]] that can be catted together
809 with a general overview of [[ifupdown]] to produce real manpages.
812 %.man: %.defn defn2man.pl
813 ./defn2man.pl $< > $@
816 So we'll use a similar structure to [[defn2c.pl]].
824 <<defn2man variables>>
827 <<defn2man subroutines>>
830 <<parse [[.defn]] file and output manpage fragment>>
833 As predicted, we'll also incorporate [[nextline]], [[match]] and
836 <<defn2man variables>>=
841 <<defn2man subroutines>>=
842 <<[[nextline]] subroutine>>
843 <<[[match]] subroutine>>
844 <<[[skip_section]] subroutine>>
847 Now we'll have a slightly different structure to the program itself
848 this time, since we need to do things pretty much in order for
849 outputting the manpage. This imposes stricter ordering requirements on
850 the [[.defn]] files than [[defn2c]] did.
852 <<parse [[.defn]] file and output manpage fragment>>=
854 if ($line and match($line, "address_family")) {
855 get_address_family $match;
857 die "address_family must be listed first\n";
859 if ($line and match($line, "architecture")) {
860 get_architecture $match;
862 while ($line and match($line, "method")) {
867 Okay, so it wasn't \emph{that} different from what we had before. Sue
870 The [[get_address_family]] and [[get_architecture]] subroutines are
871 fairly straight forward:
873 <<defn2man subroutines>>=
874 sub get_address_family {
875 print ".SH " . uc($match) . " ADDRESS FAMILY\n";
876 print "This section documents the methods available in the\n";
877 print "$match address family.\n";
882 <<defn2man subroutines>>=
883 sub get_architecture {
889 Which only leaves extracting the description and options for each
890 method. And, of course, this imposes less restrictions of the
891 [[.defn]] file than [[defn2c.pl]] did. It's a crazy old world.
893 <<defn2man subroutines>>=
896 my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
897 my $description = "";
901 while ($line and match($line, "", $indent)) {
902 if (match($line, "description", $indent)) {
903 $description = get_description();
904 } elsif (match($line, "options", $indent)) {
905 @options = get_options();
911 <<output [[$method]] introduction man fragment>>
912 <<output [[$description]] man fragment>>
913 <<output [[@options]] man fragment>>
917 <<output [[$method]] introduction man fragment>>=
918 print ".SS The $method Method\n";
921 Okay. Now our [[$description]] is just the description with any [['\n']]
922 characters it may've had, but without the leading spaces.
924 <<defn2man subroutines>>=
925 sub get_description {
927 my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
928 while(nextline && match($line, "", $indent)) {
935 We're actually going to be a little tricky here, and allow some formatting
936 in our descriptions. Basically, we'll allow bold and italic encoding
937 to be denoted by [[*bold*]] and [[/italics/]] in the wonderful Usenet
938 tradition. As such, we'll use a cute little function to convert the
939 Usenet style to \emph{roff}. We'll also take care not to do this conversion
940 within words (for things like [[/etc/hosts]], eg). Voila:
942 <<defn2man subroutines>>=
948 while ($in =~ m%^([^*/]*)([*/])([^*/]*)([*/])(.*)$%s) {
949 my ($pre, $l, $mid, $r, $post) = ($1, $2, $3, $4, $5);
950 if ($l eq $r && " $pre" =~ m/[[:punct:][:space:]]$/
951 && "$post " =~ m/^[[:punct:][:space:]]/) {
953 $out .= ($l eq "*" ? '\fB' : '\fI') . $mid . '\fP';
954 ($in = $post) =~ s/^\s+/ /;
957 $in = $mid . $r . $post;
964 The only further thing to note about this is that we're being careless
965 and ignoring the possibility of \emph{roff} escape sequences in the input. But
966 since this is for internal use only, well, too bad. So here we go:
968 <<output [[$description]] man fragment>>=
969 if ($description ne "") {
970 print usenet2man($description) . "\n";
972 print "(No description)\n";
978 Reading the options is almost exactly the same as the description,
979 except we want a list instead of just a string.
981 <<defn2man subroutines>>=
984 my $indent = ($line =~ /(\s*)\S/) ? $1 : "";
985 while(nextline && match($line, "", $indent)) {
992 Output is slightly more complicated, but not too much so.
994 <<output [[@options]] man fragment>>=
996 print ".B Options\n";
999 foreach my $o (@options) {
1000 if ($o =~ m/^\s*(\S*)\s*(.*)\s+--\s+(\S.*)$/) {
1006 print " \" $optargs\"" unless($optargs =~ m/^\s*$/);
1008 print usenet2man($dsc) . "\n";
1016 print "(No options)\n";
1021 \section{Run-time Configuration}
1023 Our module is of the usual form, and we'll make use of a few fairly standard
1024 headers. Please move along, there's nothing to see here.
1028 <<config function declarations>>
1029 <<config functions>>
1040 We'll also make use of some of our other modules. This is, after all,
1041 why we had a single header in the first place.
1047 The key function we're interested in defining here is
1048 [[read_interfaces()]], which will (wait for it) read an interfaces
1049 file. The intention is to make it really easy to deal with the
1050 vagaries of [[/etc/network/interfaces]] anywhere else.
1052 So the first question we need to deal with is ``What's a convenient
1053 form for other functions which deal with interfaces?'' Well, our
1054 answer to that is basically:
1057 \item an array of interface names that should be brought up at
1060 \item a singly linked list to represent the various mappings.
1062 \item another singly linked list to represent the interface
1063 definitions themselves.
1066 These are almost in exact correspondence with the original file.
1068 <<type definitions>>=
1069 typedef struct interfaces_file interfaces_file;
1072 <<structure definitions>>=
1073 struct interfaces_file {
1074 allowup_defn *allowups;
1075 interface_defn *ifaces;
1076 mapping_defn *mappings;
1080 So, at run-time, we first need a way of dealing with the [[auto]] and
1081 [[allow-*]] lines. We'll treat [[allow-auto]] and [[auto]] as equivalent,
1082 making that pretty straightforward:
1084 <<type definitions>>=
1085 typedef struct allowup_defn allowup_defn;
1088 <<structure definitions>>=
1089 struct allowup_defn {
1099 We also require a way of representing each interface listed in the
1100 configuration file. This naturally needs to reference an address family
1101 and method, and all the options a user may specify about an interface.
1103 <<type definitions>>=
1104 typedef struct interface_defn interface_defn;
1107 <<structure definitions>>=
1108 struct interface_defn {
1109 interface_defn *next;
1111 char *logical_iface;
1114 address_family *address_family;
1125 The last component in the above, the options, is represented by a
1126 series of name/value pairs, as follows:
1128 <<type definitions>>=
1129 typedef struct variable variable;
1132 <<structure definitions>>=
1139 In addition, we want to represent each mapping in the configuration
1140 file. This is somewhat simpler, since each mapping is entirely self
1141 contained, and doesn't need to reference previously determined address
1142 families or methods or anything.
1144 <<type definitions>>=
1145 typedef struct mapping_defn mapping_defn;
1148 <<structure definitions>>=
1149 struct mapping_defn {
1164 We can thus begin to instantiate our actual function. What we want is
1165 something that, given the name of a file, will produce the appropriate
1166 linked list of interfaces defined in it, or possibly give some sort of
1167 helpful error message. Pretty simple, hey?
1169 <<exported symbols>>=
1170 interfaces_file *read_interfaces(char *filename);
1173 <<config functions>>=
1174 interfaces_file *read_interfaces(char *filename) {
1175 <<variables local to read interfaces>>
1176 interfaces_file *defn;
1178 <<allocate defn or [[return NULL]]>>
1179 <<open file or [[return NULL]]>>
1181 while (<<we've gotten a line from the file>>) {
1182 <<process the line>>
1184 if (<<an error occurred getting the line>>) {
1185 <<report internal error and die>>
1194 <<allocate defn or [[return NULL]]>>=
1195 defn = malloc(sizeof(interfaces_file));
1199 defn->allowups = NULL;
1200 defn->mappings = NULL;
1201 defn->ifaces = NULL;
1204 \subsection{File Handling}
1206 So, the first and most obvious thing to deal with is the file
1207 handling. Nothing particularly imaginative here.
1209 <<variables local to read interfaces>>=
1214 <<open file or [[return NULL]]>>=
1215 f = fopen(filename, "r");
1216 if ( f == NULL ) return NULL;
1225 \subsection{Line Parsing}
1227 Our next problem is to work out how to read a single line from our
1228 input file. While this is nominally easy, we also want to deal nicely
1229 with things like continued lines, comments, and very long lines.
1231 So we're going to have to write and make use of a complicated little
1232 function, which we'll imaginatively call [[get_line()]]. It will need
1233 a pointer to the file it's reading from, as well as a buffer to store
1234 the line it finds. Since this buffer's size can't be known in advance
1235 we'll need to make it [[realloc()]]-able, which means we need to pass
1236 around references to both the buffer's location (which may change),
1237 and it's size (which probably will). Our function declaration is thus:
1239 <<config function declarations>>=
1240 static int get_line(char **result, size_t *result_len, FILE *f, int *line);
1243 To use it, we'll need a couple of variables to stores the buffer's
1244 location, and it's current length.
1246 <<variables local to read interfaces>>=
1251 Given these, and presuming we can actually implement the function, our
1252 key chunk can thus be implemented simply as:
1254 <<we've gotten a line from the file>>=
1255 get_line(&buf,&buf_len,f,&line)
1258 We'll also add the requirement that errors are indicated by the
1259 [[errno]] variable being non-zero, which is usual and reasonable for
1260 all the circumstances where [[get_line()]] might have problems.
1266 <<an error occurred getting the line>>=
1270 Actually defining the function is, as you'd probably imagine, a little
1271 more complicated. We begin by reading a line from the file. If it was
1272 a comment (that is, it has a [[#]] character at the first non-blank
1273 position) then we try again. Otherwise, if the line is continued
1274 (indicated by a [[\]] character at the very end of the line) we append
1275 the next line to the buffer. We go to a little bit of effort to trim
1276 whitespace, and finally return a boolean result indicating whether we
1279 <<config functions>>=
1280 static int get_line(char **result, size_t *result_len, FILE *f, int *line) {
1281 <<variables local to get line>>
1285 <<append next line to buffer, or [[return 0]]>>
1286 <<trim leading whitespace>>
1287 } while (<<line is a comment>>);
1289 while (<<buffer is continued>>) {
1290 <<remove continuation mark>>
1291 <<append next line to buffer, or [[return 0]]>>
1294 <<trim trailing whitespace>>
1300 In order to do string concatenation efficiently, we'll keep track of
1301 where the end of the line so far is --- this is thus where the
1302 terminating [[NUL]] will be by the end of the function.
1304 <<variables local to get line>>=
1308 We can thus clear the buffer by simply resetting where we append new
1309 text to the beginning of the buffer. What could be simpler?
1315 We'll be making use of the [[fgets()]] function to read the line
1316 (rather than, say, [[fgetc()]]) so to get an entire line we may have
1317 to make multiple attempts (if the line is bigger than our
1318 buffer). Realising this, and the fact that we may not have any
1319 allocated space for our buffer initially, we need a loop something
1322 <<append next line to buffer, or [[return 0]]>>=
1324 <<reallocate buffer as necessary, or [[return 0]]>>
1325 <<get some more of the line, or [[return 0]]>>
1326 } while(<<the line isn't complete>>);
1328 <<remove trailing newline>>
1332 assert( (*result)[pos] == '\0' );
1335 When reallocating the buffer, we need to make sure it increases in
1336 chunks large enough that we don't have to do this too often, but not
1337 so huge that we run out of memory just to read an 81 character line.
1338 We'll use two fairly simple heuristics for this: if we've got room to
1339 add no more than 10 characters, we may as well reallocate the buffer,
1340 and when reallocating, we want to more or less double the buffer, but
1341 we want to at least add 80 characters. So we do both.
1343 <<reallocate buffer as necessary, or [[return 0]]>>=
1344 if (*result_len - pos < 10) {
1345 char *newstr = realloc(*result, *result_len * 2 + 80);
1346 if (newstr == NULL) {
1350 *result_len = *result_len * 2 + 80;
1354 The only time we need to keep reading is when the buffer wasn't big
1355 enough for the entire line. This is indicated by a full buffer, with
1356 no newline at the end. There is, actually, one case where this can
1357 happen legitimately --- where the last line of the file is
1358 \emph{exactly} the length of the buffer. We need to detect this
1359 because [[fgets()]] will return [[NULL]] and indicate that it's hit
1360 the end of the file, but we won't want to indicate that until the
1361 \emph{next} time we try to get a line. Complicated, isn't it?
1363 <<the line isn't complete>>=
1364 pos == *result_len - 1 && (*result)[pos-1] != '\n'
1367 So having thought through all that, actually working with [[fgets()]]
1368 is fairly simple, especially since we deal with the actual errors
1369 elsewhere. All we need to do is make the call, update [[pos]] and
1370 check that the problems [[fgets()]] may have actually bother us.
1372 <<get some more of the line, or [[return 0]]>>=
1373 if (!fgets(*result + pos, *result_len - pos, f)) {
1374 if (ferror(f) == 0 && pos == 0) return 0;
1375 if (ferror(f) != 0) return 0;
1377 pos += strlen(*result + pos);
1380 [[fgets()]] leaves a [[\n]] in our buffer in some cases. We're never
1381 actually interested in it, however, so it's a good move to get rid of
1384 <<remove trailing newline>>=
1385 if (pos != 0 && (*result)[pos-1] == '\n') {
1386 (*result)[--pos] = '\0';
1391 Pretty simple, hey? Now the next thing we want to do is get rid of
1392 some of the whitespace lying about. This is all pretty basic, and just
1393 involves finding where the whitespace begins and ends, and, well,
1400 <<trim leading whitespace>>=
1403 while (isspace((*result)[first]) && (*result)[first]) {
1407 memmove(*result, *result + first, pos - first + 1);
1412 <<trim trailing whitespace>>=
1413 while (isspace((*result)[pos-1])) { /* remove trailing whitespace */
1416 (*result)[pos] = '\0';
1419 As we mentioned earlier, a line is a comment iff it's first character
1420 is a [[#]] symbol. Similarly, it's continued iff it's very last
1421 character is a [[\]]. And, rather obviously, if we want to remove a
1422 single trailing [[\]], we can do so by changing it to a [[NUL]].
1424 <<line is a comment>>=
1428 <<buffer is continued>>=
1429 (*result)[pos-1] == '\\'
1432 <<remove continuation mark>>=
1433 (*result)[--pos] = '\0';
1436 \subsection{Line Processing}
1438 So. We've gone to a lot of trouble to get a line that we can parse
1439 with a snap of our fingers, so we probably better jump to it, to mix
1440 some \emph{clich\'e's}.
1442 We have two alternative bits of state to maintain between lines: either
1443 what interface we're currently defining, or what mapping we're currently
1446 <<variables local to read interfaces>>=
1447 interface_defn *currif = NULL;
1448 mapping_defn *currmap = NULL;
1449 enum { NONE, IFACE, MAPPING } currently_processing = NONE;
1452 Since our configuration files are pretty basic, we can work out what
1453 any particular line means based on the first word in it. To cope with
1454 this, we'll thus make use of a couple of variables, one to store the
1455 first word, and the other to store the rest of the line.
1457 <<variables local to read interfaces>>=
1462 To initialize these variables we'll make use of a function I'm overly
1463 fond of called [[next_word()]]. It copies the first word in a string
1464 to a given buffer, and returns a pointer to the rest of the buffer.
1466 <<config function declarations>>=
1467 static char *next_word(char *buf, char *word, int maxlen);
1470 <<config functions>>=
1471 static char *next_word(char *buf, char *word, int maxlen) {
1472 if (!buf) return NULL;
1473 if (!*buf) return NULL;
1475 while(!isspace(*buf) && *buf) {
1476 if (maxlen-- > 1) *word++ = *buf;
1479 if (maxlen > 0) *word = '\0';
1481 while(isspace(*buf) && *buf) buf++;
1487 So after all this, there are basically three different sorts of line
1488 we can get: the start of a new interface, the start of a new mapping,
1489 or an option for whatever interface we're currently working with.
1490 Note that we check for blank lines, but \emph{not} for options with
1491 empty values. This has to be done on a case-by-case basis.
1493 <<process the line>>=
1494 rest = next_word(buf, firstword, 80);
1495 if (rest == NULL) continue; /* blank line */
1497 if (strcmp(firstword, "mapping") == 0) {
1498 <<process [[mapping]] line>>
1499 currently_processing = MAPPING;
1500 } else if (strcmp(firstword, "iface") == 0) {
1501 <<process [[iface]] line>>
1502 currently_processing = IFACE;
1503 } else if (strcmp(firstword, "auto") == 0) {
1504 <<process [[auto]] line>>
1505 currently_processing = NONE;
1506 } else if (strncmp(firstword, "allow-", 6) == 0 && strlen(firstword) > 6) {
1507 <<process [[allow-]] line>>
1508 currently_processing = NONE;
1510 <<process option line>>
1514 <<process option line>>=
1515 switch(currently_processing) {
1517 <<process iface option line>>
1520 <<process mapping option line>>
1524 <<report bad option and die>>
1528 \subsubsection{Mapping Line}
1530 Declaring a new mapping is reasonably copewithable --- we need to process
1531 a few things, but they're reasonably easy to handle.
1533 The main weirdness is that we're processing the [[mapping]] line itself
1534 and the rest of the stanza in separate blocks of code. So this first
1535 chunk just needs to do the basics of initialising the data structure,
1536 but can't really fill in all that much of it.
1538 <<process [[mapping]] line>>=
1539 <<allocate new mapping>>
1540 <<parse mapping interfaces>>
1541 <<set other mapping options to defaults>>
1542 <<add to list of mappings>>
1545 <<allocate new mapping>>=
1546 currmap = malloc(sizeof(mapping_defn));
1547 if (currmap == NULL) {
1548 <<report internal error and die>>
1552 <<parse mapping interfaces>>=
1553 currmap->max_matches = 0;
1554 currmap->n_matches = 0;
1555 currmap->match = NULL;
1557 while((rest = next_word(rest, firstword, 80))) {
1558 if (currmap->max_matches == currmap->n_matches) {
1560 currmap->max_matches = currmap->max_matches * 2 + 1;
1561 tmp = realloc(currmap->match,
1562 sizeof(*tmp) * currmap->max_matches);
1564 currmap->max_matches = (currmap->max_matches - 1) / 2;
1565 <<report internal error and die>>
1567 currmap->match = tmp;
1570 currmap->match[currmap->n_matches++] = strdup(firstword);
1574 <<set other mapping options to defaults>>=
1575 currmap->script = NULL;
1577 currmap->max_mappings = 0;
1578 currmap->n_mappings = 0;
1579 currmap->mapping = NULL;
1582 <<add to list of mappings>>=
1584 mapping_defn **where = &defn->mappings;
1585 while(*where != NULL) {
1586 where = &(*where)->next;
1589 currmap->next = NULL;
1593 So that's that. But as mentioned, we also need to cope with the options
1594 within the stanza, as well as the lead in. As before, it's not really
1595 complicated, and we do it thusly:
1597 <<process mapping option line>>=
1598 if (strcmp(firstword, "script") == 0) {
1599 <<handle [[script]] line>>
1600 } else if (strcmp(firstword, "map") == 0) {
1601 <<handle [[map]] line>>
1603 <<report bad option and die>>
1607 <<handle [[script]] line>>=
1608 if (currmap->script != NULL) {
1609 <<report duplicate script in mapping and die>>
1611 currmap->script = strdup(rest);
1615 <<handle [[map]] line>>=
1616 if (currmap->max_mappings == currmap->n_mappings) {
1618 currmap->max_mappings = currmap->max_mappings * 2 + 1;
1619 opt = realloc(currmap->mapping, sizeof(*opt) * currmap->max_mappings);
1621 <<report internal error and die>>
1623 currmap->mapping = opt;
1625 currmap->mapping[currmap->n_mappings] = strdup(rest);
1626 currmap->n_mappings++;
1629 \subsubsection{Interface line}
1631 Declaring a new interface follows the same pattern, but is somewhat more
1632 interesting and some more complicated data structures are involved.
1634 <<process [[iface]] line>>=
1636 <<variables local to process [[iface]] line>>
1638 <<allocate new interface>>
1640 <<parse interface settings>>
1643 <<set address family>>
1645 <<set other interface options to defaults>>
1647 <<add to list of interfaces>>
1651 We'll deal with each of these phases one by one and pretty much in
1652 order, so prepare yourself for the intense excitement of memory
1655 <<allocate new interface>>=
1656 currif = malloc(sizeof(interface_defn));
1658 <<report internal error and die>>
1662 When we introduce a new interface, we simultaneously name the
1663 interface, the address family, and the method. We cope with this by,
1664 well, getting somewhere to store each of them, and then, well, storing
1667 <<variables local to process [[iface]] line>>=
1668 char iface_name[80];
1669 char address_family_name[80];
1670 char method_name[80];
1673 <<parse interface settings>>=
1674 rest = next_word(rest, iface_name, 80);
1675 rest = next_word(rest, address_family_name, 80);
1676 rest = next_word(rest, method_name, 80);
1679 <<report too few parameters for iface line and die>>
1682 if (rest[0] != '\0') {
1683 <<report too many parameters for iface line and die>>
1687 We then want to store the interface name.
1690 currif->logical_iface = strdup(iface_name);
1691 if (!currif->logical_iface) {
1692 <<report internal error and die>>
1696 Setting the address family is a little more involved, because it's not
1697 very useful to know what the name of the address family is, you really
1698 want to know all the details recorded in the appropriate
1699 [[address_family]] structure. So we'll make use of a little helper
1700 function, called [[get_address_family()]] to convert the useless
1701 string, to the hopefully less useless structure.
1703 <<config function declarations>>=
1704 static address_family *get_address_family(address_family *af[], char *name);
1707 <<set address family>>=
1708 currif->address_family = get_address_family(addr_fams, address_family_name);
1709 if (!currif->address_family) {
1710 <<report unknown address family and die>>
1714 Of course, we probably need to actually implement the function too. We
1715 won't do anything particularly fancy here, just a simple linear
1716 search. \emph{Should this really be here, or an exported symbol from
1717 [[addrfam.c]]? --- aj}
1719 <<config functions>>=
1720 static address_family *get_address_family(address_family *af[], char *name) {
1722 for (i = 0; af[i]; i++) {
1723 if (strcmp(af[i]->name, name) == 0) {
1731 We do something incredibly similar when dealing with the method the
1732 user wishes to use, and we do it for incredibly similar reasons. Again
1733 we declare a cute little helper function, this time imaginatively
1734 called [[get_method()]], and then go and use it and implement in
1735 almost exactly the same way as before. I told you this was going to be
1736 a thrill. \emph{The same note applies here, too --- aj}
1738 <<config function declarations>>=
1739 static method *get_method(address_family *af, char *name);
1743 currif->method = get_method(currif->address_family, method_name);
1744 if (!currif->method) {
1745 <<report unknown method and die>>
1746 return NULL; /* FIXME */
1750 <<config functions>>=
1751 static method *get_method(address_family *af, char *name) {
1753 for (i = 0; i < af->n_methods; i++) {
1754 if (strcmp(af->method[i].name, name) == 0) {
1755 return &af->method[i];
1762 You'll continue to be enthralled as we set the remaining options to
1763 some default values.
1765 <<set other interface options to defaults>>=
1766 currif->automatic = 1;
1767 currif->max_options = 0;
1768 currif->n_options = 0;
1769 currif->option = NULL;
1772 Since we want to keep the interfaces in order, we have to go all the
1773 way to the end of the list of interfaces to add the new interface, and
1774 we can hence set the [[next]] pointer to NULL in all cases. Gee. Whiz.
1776 Actually, I'm selling this a little short. We also want to make sure
1777 we don't try instantiating the same interface twice or anything. So we
1778 take care of that too. There now. Didn't that just get the adrenalin
1781 <<add to list of interfaces>>=
1783 interface_defn **where = &defn->ifaces;
1784 while(*where != NULL) {
1785 if (duplicate_if(*where, currif)) {
1786 <<report duplicate interface and die>>
1788 where = &(*where)->next;
1792 currif->next = NULL;
1796 Duplicate interfaces are interfaces that have the same name and the
1797 same address family. Nothing more complicated than that.
1799 <<config function declarations>>=
1800 static int duplicate_if(interface_defn *ifa, interface_defn *ifb);
1803 <<config functions>>=
1804 static int duplicate_if(interface_defn *ifa, interface_defn *ifb) {
1805 if (strcmp(ifa->logical_iface, ifb->logical_iface) != 0) return 0;
1806 if (ifa->address_family != ifb->address_family) return 0;
1811 Dealing with the per-interface options is the next thing to deal
1814 <<process iface option line>>=
1815 <<convert [[post-up]] and [[pre-down]] aliases to [[up]] and [[down]]>>
1816 <<check for duplicate options>>
1820 <<convert [[post-up]] and [[pre-down]] aliases to [[up]] and [[down]]>>=
1821 if (strcmp(firstword, "post-up") == 0) {
1822 strcpy(firstword, "up");
1824 if (strcmp(firstword, "pre-down") == 0) {
1825 strcpy(firstword, "down");
1829 <<check for duplicate options>>=
1833 if (strlen (rest) == 0) {
1834 <<report empty option and die>>
1837 if (strcmp(firstword, "pre-up") != 0
1838 && strcmp(firstword, "up") != 0
1839 && strcmp(firstword, "down") != 0
1840 && strcmp(firstword, "post-down") != 0)
1842 for (i = 0; i < currif->n_options; i++) {
1843 if (strcmp(currif->option[i].name, firstword) == 0) {
1844 <<report duplicate option and die>>
1851 Adding an option is fairly straightforward: we simply construct
1852 a new variable and add it at the end of our array of variables,
1853 increasing the size of the array first if necessary. Options with
1854 empty values are rejected.
1857 if (currif->n_options >= currif->max_options) {
1858 <<increase max number of options>>
1861 currif->option[currif->n_options].name = strdup(firstword);
1862 currif->option[currif->n_options].value = strdup(rest);
1864 if (!currif->option[currif->n_options].name) {
1865 <<report internal error and die>>
1868 if (!currif->option[currif->n_options].value) {
1869 <<report internal error and die>>
1872 currif->n_options++;
1875 We'll increase the space for variables by a constant amount each time,
1876 rather than doubling or anything smart like that.
1878 <<increase max number of options>>=
1881 currif->max_options = currif->max_options + 10;
1882 opt = realloc(currif->option, sizeof(*opt) * currif->max_options);
1884 <<report internal error and die>>
1886 currif->option = opt;
1890 \subsubsection{Auto and Allow Lines}
1892 Processing the [[auto]] and [[allow-]] lines is pretty straightforward
1893 after the above, we just need to add each parameter to the list and
1894 check for duplicates. Since we're doing essentially the same thing twice,
1895 we'll break the common part out into a function.
1897 <<process [[auto]] line>>=
1898 allowup_defn *auto_ups = get_allowup(&defn->allowups, "auto");
1900 <<report internal error and die>>
1902 while((rest = next_word(rest, firstword, 80))) {
1903 if (!add_allow_up(filename, line, auto_ups, firstword))
1907 <<process [[allow-]] line>>=
1908 allowup_defn *allow_ups = get_allowup(&defn->allowups, firstword + 6);
1910 <<report internal error and die>>
1912 while((rest = next_word(rest, firstword, 80))) {
1913 if (!add_allow_up(filename, line, allow_ups, firstword))
1918 <<config function declarations>>=
1919 allowup_defn *get_allowup(allowup_defn **allowups, char *name);
1921 <<config functions>>=
1922 allowup_defn *get_allowup(allowup_defn **allowups, char *name) {
1923 for (; *allowups; allowups = &(*allowups)->next) {
1924 if (strcmp((*allowups)->when, name) == 0) break;
1926 if (*allowups == NULL) {
1927 *allowups = malloc(sizeof(allowup_defn));
1928 if (*allowups == NULL) return NULL;
1929 (*allowups)->when = strdup(name);
1930 (*allowups)->next = NULL;
1931 (*allowups)->max_interfaces = 0;
1932 (*allowups)->n_interfaces = 0;
1933 (*allowups)->interfaces = NULL;
1939 We'll want to export a little helper function to make finding the appropriate
1942 <<exported symbols>>=
1943 allowup_defn *find_allowup(interfaces_file *defn, char *name);
1946 <<config functions>>=
1947 allowup_defn *find_allowup(interfaces_file *defn, char *name) {
1948 allowup_defn *allowups = defn->allowups;
1949 for (; allowups; allowups = allowups->next) {
1950 if (strcmp(allowups->when, name) == 0) break;
1956 <<config function declarations>>=
1957 allowup_defn *add_allow_up(char *filename, int line,
1958 allowup_defn *allow_up, char *iface_name);
1961 <<config functions>>=
1962 allowup_defn *add_allow_up(char *filename, int line,
1963 allowup_defn *allow_up, char *iface_name)
1965 <<check [[iface_name]] isn't already an [[allow_up]] interface or die>>
1966 <<add [[iface_name]] as an [[allow_up]] interface or die>>
1971 <<check [[iface_name]] isn't already an [[allow_up]] interface or die>>=
1975 for (i = 0; i < allow_up->n_interfaces; i++) {
1976 if (strcmp(iface_name, allow_up->interfaces[i]) == 0) {
1977 <<report [[iface_name]] as [[allow_up]] duplicate, die>>
1983 <<add [[iface_name]] as an [[allow_up]] interface or die>>=
1984 if (allow_up->n_interfaces == allow_up->max_interfaces) {
1986 allow_up->max_interfaces *= 2;
1987 allow_up->max_interfaces++;
1988 tmp = realloc(allow_up->interfaces,
1989 sizeof(*tmp) * allow_up->max_interfaces);
1991 <<report internal error and die>>
1993 allow_up->interfaces = tmp;
1996 allow_up->interfaces[allow_up->n_interfaces] = strdup(iface_name);
1997 allow_up->n_interfaces++;
2000 \subsection{Error Handling}
2002 We don't do anything too fancy about handling errors that occur, we
2003 just print out a hopefully helpful error message, and return from the
2004 function. \emph{We probably should also go to some effort to close files,
2005 and free memory, but well, you know. Maybe version $n+1$. --- aj}
2007 <<report internal error and die>>=
2012 <<report too few parameters for iface line and die>>=
2013 fprintf(stderr, "%s:%d: too few parameters for iface line\n", filename, line);
2017 <<report too many parameters for iface line and die>>=
2018 fprintf(stderr, "%s:%d: too many parameters for iface line\n", filename, line);
2022 <<report unknown address family and die>>=
2023 fprintf(stderr, "%s:%d: unknown address type\n", filename, line);
2027 <<report unknown method and die>>=
2028 fprintf(stderr, "%s:%d: unknown method\n", filename, line);
2032 <<report duplicate interface and die>>=
2033 fprintf(stderr, "%s:%d: duplicate interface\n", filename, line);
2037 <<report [[iface_name]] as [[allow_up]] duplicate, die>>=
2038 fprintf(stderr, "%s:%d: interface %s declared allow-%s twice\n",
2039 filename, line, iface_name, allow_up->when);
2043 <<report duplicate option and die>>=
2044 fprintf(stderr, "%s:%d: duplicate option\n", filename, line);
2048 <<report duplicate script in mapping and die>>=
2049 fprintf(stderr, "%s:%d: duplicate script in mapping\n", filename, line);
2053 <<report bad option and die>>=
2054 fprintf(stderr, "%s:%d: misplaced option\n", filename, line);
2058 <<report empty option and die>>=
2059 fprintf(stderr, "%s:%d: option with empty value\n", filename, line);
2065 The [[execute]] module will be laid out in the standard manner, and
2066 will make use of the usual header files.
2070 <<execute global variables>>
2071 <<execute function declarations>>
2072 <<execute functions>>
2075 <<execute headers>>=
2085 The key functions we export from here are all the functions that as a
2086 fairly direct result run some executable.
2089 \item [[iface_up()]] and [[iface_down()]] which will actually
2090 configure or deconfigure an interface.
2092 \item [[execute()]] which will take an interface definition and
2093 a command and fill in the details from the first into the
2094 second, and the execute the result. This is basically just a
2095 callback for the address family module.
2097 \item [[run_mapping()]] which will run a mapping script and
2098 determine if a new logical interface should be selected.
2101 We'll discuss each of these in order.
2103 \subsection{Interface Configuration and Deconfiguration}
2105 Most of the complexity is involved in implementing the [[iface_up()]] and
2106 [[iface_down()]] functions. These are complicated enough that an explanatory
2107 diagram is probably useful:
2110 \includegraphics[height=60mm]{execution}
2113 At a conceptual level, [[iface_up()]] and [[iface_down()]] have a
2114 reasonably straightforward job: they have to run one set of scripts,
2115 the configure or deconfigure the interface, then run another set of
2118 This is complicated slightly in that they also have to handle the
2119 possibility that some of an interface's required arguments may be missing
2120 (in which case none of the commands should be attempted), and that some
2121 of the commands may fail (in which case none of the following commands
2122 should be attempted). We've already encoded most of the early-abort
2123 logic for the latter case into the address family definitions; so the way
2124 we'll handle the the former case is simply to call the address family's
2125 method [[up()]] or [[down()]] twice: once to ensure all the variables are
2126 appropriately filled out, and once to actually configure the interface.
2128 \subsubsection{Command checking}
2130 As such, we'll make use of two execution functions, each of which take
2131 one parameter, a shell command. We'll uninventively call these [[doit()]]
2132 and [[check()]]. They'll return 0 on failure, non-zero on success.
2134 [[check()]] is thus fairly trivial:
2136 <<execute function declarations>>=
2137 static int check(char *str);
2140 <<execute functions>>=
2141 static int check(char *str) {
2146 \subsubsection{Environment handling}
2148 [[doit()]] is much more complicated, mainly by the fact that we
2149 don't simply want to just run the programs, but because we also want
2150 to setup a sanitized environment. In particular, we want to make the
2151 environment variables [[IFACE]], and [[MODE]] available (eg, [[eth0]] and
2152 [[start]] respectively), and we want to export all the given options as
2153 [[IF_OPTION]], with some sanitisation.
2155 We'll do this just once per interface rather than once per command,
2156 and so we'll use a global variable to store our new environment, and a
2157 special function which will initialise it for us.
2159 <<execute global variables>>=
2160 static char **environ = NULL;
2163 [[environ]] will be in the format used by the [[execle()]] function call,
2164 that is, a [[NULL]]-terminated array of strings of the form [[foo=bar]].
2166 <<execute function declarations>>=
2167 static void set_environ(interface_defn *iface, char *mode, char *phase);
2170 Our function then will be:
2172 <<execute functions>>=
2173 static void set_environ(interface_defn *iface, char *mode, char *phase) {
2174 <<variables local to set environ>>
2176 const int n_env_entries = iface->n_options + 8;
2178 <<initialise environ [[n_env_entries]]>>
2180 for (i = 0; i < iface->n_options; i++) {
2181 <<[[continue]] if option is a command>>
2183 <<add [[IF_]]option to environment>>
2186 <<add [[IFACE]] to environment>>
2187 <<add [[LOGICAL]] to environment>>
2188 <<add [[ADDRFAM]] to environment>>
2189 <<add [[METHOD]] to environment>>
2191 <<add [[MODE]] to environment>>
2192 <<add [[PHASE]] to environment>>
2193 <<add [[VERBOSITY]] to environment>>
2194 <<add [[PATH]] to environment>>
2198 Since we keep adding at the end, we'll make use of a pointer to keep track
2199 of where the end actually is, namely:
2201 <<variables local to set environ>>=
2205 Initialising thus becomes:
2207 <<initialise environ [[n_env_entries]]>>=
2208 <<clear environ if necessary>>
2209 environ = malloc(sizeof(char*) * (n_env_entries + 1 /* for final NULL */));
2210 environend = environ;
2214 <<clear environ if necessary>>=
2215 if (environ != NULL) {
2217 for (ppch = environ; *ppch; ppch++) {
2226 Our continue chunk is also fairly straight forward:
2228 <<[[continue]] if option is a command>>=
2229 if (strcmp(iface->option[i].name, "pre-up") == 0
2230 || strcmp(iface->option[i].name, "up") == 0
2231 || strcmp(iface->option[i].name, "down") == 0
2232 || strcmp(iface->option[i].name, "post-down") == 0)
2238 We'll make use of a small helper function for actually setting the
2239 environment. This function will handle [[malloc]]ing enough memory, and
2240 ensuring the environment variable name is reasonably sensible. It'll
2241 take three parameters: a [[printf]]-style format string presumed to
2242 contain two [[%s]]s, and the two parameters to that format string.
2244 <<execute function declarations>>=
2245 static char *setlocalenv(char *format, char *name, char *value);
2248 We can then go ahead and fill in the environment.
2250 <<add [[IF_]]option to environment>>=
2251 *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
2252 iface->option[i].value);
2256 <<add [[IFACE]] to environment>>=
2257 *(environend++) = setlocalenv("%s=%s", "IFACE", iface->real_iface);
2261 <<add [[LOGICAL]] to environment>>=
2262 *(environend++) = setlocalenv("%s=%s", "LOGICAL", iface->logical_iface);
2266 <<add [[MODE]] to environment>>=
2267 *(environend++) = setlocalenv("%s=%s", "MODE", mode);
2271 <<add [[PHASE]] to environment>>=
2272 *(environend++) = setlocalenv("%s=%s", "PHASE", phase);
2276 <<add [[PATH]] to environment>>=
2277 *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
2281 <<add [[VERBOSITY]] to environment>>=
2282 *(environend++) = setlocalenv("%s=%s", "VERBOSITY", verbose ? "1" : "0");
2286 <<add [[ADDRFAM]] to environment>>=
2287 *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
2291 <<add [[METHOD]] to environment>>=
2292 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
2296 Our helper function then will then be something like:
2298 <<execute functions>>=
2299 static char *setlocalenv(char *format, char *name, char *value) {
2302 <<allocate memory for [[result]]>>
2304 sprintf(result, format, name, value);
2312 Allocating the memory is fairly straightforward (although working out
2313 exactly how much memory involves a little guesswork, and assuming the
2314 caller passes in a reasonable [[format]]).
2316 <<allocate memory for [[result]]>>=
2317 result = malloc(strlen(format) /* -4 for the two %s's */
2327 And finally, tidying the result is a fairly simple matter of eliding all
2328 the characters we don't like, or translating them to ones we do like. We
2329 do like upper case letters, digits and underscores; and we're willing
2330 to translate hyphens and lower case letters. So here we go.
2332 <<tidy [[result]]>>=
2336 for(here = there = result; *there != '=' && *there; there++) {
2337 if (*there == '-') *there = '_';
2338 if (isalpha(*there)) *there = toupper(*there);
2340 if (isalnum(*there) || *there == '_') {
2345 memmove(here, there, strlen(there) + 1);
2349 \subsubsection{Command Execution}
2351 Our [[doit()]] function is then essentially a rewrite of the standard
2352 [[system()]] function call. The only additions are that we setup our
2353 child's environment as discussed previously, and we make use of two
2354 external globals, [[no_act]] and [[verbose]] and modify our behaviour
2357 <<execute function declarations>>=
2358 static int doit(char *str);
2361 <<execute functions>>=
2362 static int doit(char *str) {
2365 if (verbose || no_act) {
2366 fprintf(stderr, "%s\n", str);
2373 switch(child = fork()) {
2374 case -1: /* failure */
2377 execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
2379 default: /* parent */
2382 waitpid(child, &status, 0);
2383 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
2390 \subsubsection{Executing a list of commands}
2392 In addition to the above, we also need a function to cope with running
2393 all the [[pre-up]] commands and so forth.
2395 <<exported symbols>>=
2396 int execute_all(interface_defn *ifd, execfn *exec, char *opt);
2399 All we need to do for this is to iterate through the options in the
2400 interface definition, and execute whichever ones are the right type,
2401 and call the [[run-parts]] command on the appropriate directory of
2402 scripts. That doesn't make for thrilling code.
2404 This function will generally have [[doit]] passed in as the [[exec]]
2407 <<execute functions>>=
2408 int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
2411 for (i = 0; i < ifd->n_options; i++) {
2412 if (strcmp(ifd->option[i].name, opt) == 0) {
2413 if (!(*exec)(ifd->option[i].value)) {
2419 snprintf(buf, sizeof(buf), "run-parts %s /etc/network/if-%s.d",
2420 verbose ? "--verbose" : "", opt);
2428 \subsubsection{[[iface_up()]] and [[iface_down()]]}
2430 Our functions, then are:
2432 <<exported symbols>>=
2433 int iface_up(interface_defn *iface);
2434 int iface_down(interface_defn *iface);
2437 <<execute functions>>=
2438 int iface_up(interface_defn *iface) {
2439 if (!iface->method->up(iface,check)) return -1;
2441 set_environ(iface, "start", "pre-up");
2442 if (!execute_all(iface,doit,"pre-up")) return 0;
2444 if (!iface->method->up(iface,doit)) return 0;
2446 set_environ(iface, "start", "post-up");
2447 if (!execute_all(iface,doit,"up")) return 0;
2453 <<execute functions>>=
2454 int iface_down(interface_defn *iface) {
2455 if (!iface->method->down(iface,check)) return -1;
2457 set_environ(iface, "stop", "pre-down");
2458 if (!execute_all(iface,doit,"down")) return 0;
2460 if (!iface->method->down(iface,doit)) return 0;
2462 set_environ(iface, "stop", "post-down");
2463 if (!execute_all(iface,doit,"post-down")) return 0;
2469 \subsection{Command Parsing}
2471 All the above just leave one thing out: how the address family method's
2472 configuration function gets back to calling [[doit()]]. This function
2473 answers that question:
2475 <<exported symbols>>=
2476 int execute(char *command, interface_defn *ifd, execfn *exec);
2479 At the somewhat abstract level, this is fairly trivial. The devil is
2480 in the details of the parsing, which makes up the rest of the module.
2482 <<execute functions>>=
2483 int execute(char *command, interface_defn *ifd, execfn *exec) {
2487 out = parse(command, ifd);
2488 if (!out) { return 0; }
2497 We'll need a basic parser function, which we'll call [[parse()]], to
2498 make the appropriate substitutions into a command. It's probably worth
2499 a note as to exactly what substitutions may be made:
2503 \item Special characters can be escaped with a backslash. eg
2504 [[ls MoreThan80\%]].
2506 \item Variables can be substituted by including their name
2507 delimeted by percents. eg [[ls %directory%]].
2509 \item Optional components may be enclosed in double square
2510 brackets. Optional components will be included exactly when
2511 every variable referenced within exists. eg
2512 [[ls [[--color=%color%]]][[] %directory%]]. Optional components
2517 Most of the parsing is fairly straightforward -- basically, we keep an
2518 output buffer, and add things to it as we stroll through the input
2519 buffer: either the actual character we want, or whatever the value of
2520 the variable we're looking at is, or whatever. The only particularly
2521 complicated bit is how we deal with the optional sections, which will
2522 be explained when we get to them.
2524 <<execute function declarations>>=
2525 static char *parse(char *command, interface_defn *ifd);
2528 <<execute functions>>=
2529 static char *parse(char *command, interface_defn *ifd) {
2530 <<variables local to parse>>
2538 <<deal with error conditions>>
2544 \subsubsection{Maintain output buffer}
2546 So the first thing we need to do is actually write some code to deal
2547 with the output buffer, which will need to be dynamically resized and
2548 so on to take care of possibly long strings and what-not. It is the
2549 caller's responsibility to [[free()]] this buffer. We'll maintain two
2550 extra variables for convenience: who much memory we've allocated
2551 [[len]], and where the next character should be stuck [[pos]].
2553 <<variables local to parse>>=
2554 char *result = NULL;
2555 size_t pos = 0, len = 0;
2558 This makes it pretty easy to return the result to the caller, too.
2564 The main thing to be done to this buffer is to add characters or
2565 strings to it. To deal with this, we'll make use of an [[addstr()]]
2566 function that resizes the buffer as necessary, and appends a string to
2567 it. So we can deal with single characters, and substrings in general,
2568 we'll specify the string to be added as a pointer-length combination,
2569 rather than as a [[NUL]] terminated string.
2571 <<execute function declarations>>=
2572 void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
2575 <<execute functions>>=
2576 void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen) {
2577 assert(*len >= *pos);
2578 assert(*len == 0 || (*buf)[*pos] == '\0');
2580 if (*pos + strlen >= *len) {
2582 newbuf = realloc(*buf, *len * 2 + strlen + 1);
2585 exit(1); /* a little ugly */
2588 *len = *len * 2 + strlen + 1;
2591 while (strlen-- >= 1) {
2592 (*buf)[(*pos)++] = *str;
2595 (*buf)[*pos] = '\0';
2599 Given this, we can define our default behaviour for a character:
2603 addstr(&result, &len, &pos, command, 1);
2608 \subsubsection{Escaped characters}
2610 We can also deal pretty simply with escaped tokens. The only special
2611 circumstance is if the [[\]] is at the very end of string. We don't
2612 want buffer overflows afterall.
2617 addstr(&result, &len, &pos, command+1, 1);
2620 addstr(&result, &len, &pos, command, 1);
2626 \subsubsection{Optional components}
2628 Basically we keep track of each optional section we're in, whether
2629 we've been unable to fill in any variables, and where we started
2630 it. When we reach the end of an optional section, we check to see if
2631 we were unable to fill in any variables, and, if so, we discard any
2632 text we'd added within that block. This also allows us to neatly check
2633 for any errors trying to fill in variables that aren't in optional
2636 Basically what we'll do here is keep one stack to represent where the
2637 various thingos started, and another to represent whether any
2638 variables didn't exist. We'll use the bottom-most entry in the stack
2639 to represent the entire command, and thus keep track of whether or not
2640 we have to return an error because an undefined variable was used in a
2641 non-optional part of the command.
2643 <<constant definitions>>=
2644 #define MAX_OPT_DEPTH 10
2647 <<variables local to parse>>=
2648 size_t old_pos[MAX_OPT_DEPTH] = {0};
2649 int okay[MAX_OPT_DEPTH] = {1};
2653 Given this, when we encounter a double open bracket, we need to just
2654 add the appropriate values to our stacks, and, similarly, when we
2655 encounter a double close bracket, we simply need to pop the stack, and
2656 see whether we need to move back or not, as well as taking care of an
2657 possible errors, naturally. \emph{We probably could actually give
2658 error messages here instead of just treating the brackets literally
2659 when they might cause problems. But there doesn't seem much point,
2664 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
2665 old_pos[opt_depth] = pos;
2666 okay[opt_depth] = 1;
2670 addstr(&result, &len, &pos, "[", 1);
2678 if (command[1] == ']' && opt_depth > 1) {
2680 if (!okay[opt_depth]) {
2681 pos = old_pos[opt_depth];
2686 addstr(&result, &len, &pos, "]", 1);
2692 Finally, at the end of the function, the stacks can be left in an
2693 unacceptable state --- either one of the optional blocks was never
2694 closed, or an undefined variable was used elsewhere. We'll note these
2695 circumstances by returning [[NULL]] and setting [[errno]].
2697 <<execute headers>>=
2701 <<constant definitions>>=
2702 #define EUNBALBRACK 10001
2703 #define EUNDEFVAR 10002
2706 <<deal with error conditions>>=
2707 if (opt_depth > 1) {
2708 errno = EUNBALBRACK;
2720 \subsubsection{Variables}
2722 Dealing with variables is comparatively fairly simple. We just need to
2723 find the next percent, and see if whatever's in-between is a variable,
2724 and, if so, get it's value.
2726 <<constant definitions>>=
2727 #define MAX_VARNAME 32
2728 #define EUNBALPER 10000
2734 <<variables local to handle percent token>>
2737 <<determine variable name>>
2739 <<get [[varvalue]]>>
2742 addstr(&result, &len, &pos, varvalue, strlen(varvalue));
2744 okay[opt_depth - 1] = 0;
2747 <<move to token after closing percent>>
2753 We don't do anything particularly clever dealing with the next percent
2754 --- just a pointer to the appropriate character.
2756 <<variables local to handle percent token>>=
2760 <<determine variable name>>=
2762 nextpercent = strchr(command, '%');
2770 <<move to token after closing percent>>=
2771 command = nextpercent + 1;
2774 The slightly tricky thing we do here is use a [[strncmpz]] function,
2775 which allows us to check that a string represented by a [[char*]] and
2776 a length is the same as a [[NUL]] terminated string.
2778 <<execute function declarations>>=
2779 int strncmpz(char *l, char *r, size_t llen);
2782 <<execute functions>>=
2783 int strncmpz(char *l, char *r, size_t llen) {
2784 int i = strncmp(l, r, llen);
2792 Given the above, the implementation of the [[get_var()]] function to
2793 lookup the value of a variable, is reasonably straight forward.
2795 <<execute function declarations>>=
2796 char *get_var(char *id, size_t idlen, interface_defn *ifd);
2799 <<execute functions>>=
2800 char *get_var(char *id, size_t idlen, interface_defn *ifd) {
2803 if (strncmpz(id, "iface", idlen) == 0) {
2804 return ifd->real_iface;
2806 for (i = 0; i < ifd->n_options; i++) {
2807 if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
2808 return ifd->option[i].value;
2817 Which means we can finish of the chunk, thus:
2819 <<get [[varvalue]]>>=
2820 varvalue = get_var(command, nextpercent - command, ifd);
2823 \subsection{Mapping Scripts}
2825 Doing a mapping is moderately complicated, since we need to pass a
2826 fair bit of stuff to the script. The way we'll do this is via a
2827 mixture of command line arguments, and [[stdin]]: basically, we'll
2828 pass all the mapping variables from the interfaces file via [[stdin]],
2829 and anything else necessary will be a command line argument. The
2830 script will be expected to exit successfully with the appropriate
2831 logical interface as the first line of [[stdout]] if it made a match,
2832 or exit unsuccessfully (error code [[1]], eg) otherwise.
2834 <<exported symbols>>=
2835 int run_mapping(char *physical, char *logical, int len, mapping_defn *map);
2838 <<execute functions>>=
2839 int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
2844 <<execute the mapping script>>
2845 <<send input to mapping script>>
2846 <<wait for mapping script to finish>>
2847 <<check output from mapping script>>
2853 The latter options here are fairly straightforward, given some Unix
2856 <<send input to mapping script>>=
2857 for (i = 0; i < map->n_mappings; i++) {
2858 fprintf(in, "%s\n", map->mapping[i]);
2863 <<wait for mapping script to finish>>=
2864 waitpid(pid, &status, 0);
2867 <<check output from mapping script>>=
2868 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
2869 if (fgets(logical, len, out)) {
2870 char *pch = logical + strlen(logical) - 1;
2871 while (pch >= logical && isspace(*pch))
2878 Slightly more complicated is setting up the child process and grabbing
2879 its [[stdin]] and [[stdout]]. Unfortunately we can't just use
2880 [[popen()]] for this, since it'll only allow us to go one way. So,
2881 instead we'll write our own [[popen()]]. It'll look like:
2883 <<execute headers>>=
2887 <<execute function declarations>>=
2888 static int popen2(FILE **in, FILE **out, char *command, ...);
2891 The varargs component will be the arguments, as per [[execl()]], and
2892 the return value will be the [[PID]] if the call was successful, or 0
2895 As such, we will be able to execute the script thusly:
2897 <<execute the mapping script>>=
2898 pid = popen2(&in, &out, map->script, physical, NULL);
2904 Writing [[popen2()]] is an exercise in Unix arcana.
2906 <<execute headers>>=
2908 #include <sys/wait.h>
2911 <<execute functions>>=
2912 static int popen2(FILE **in, FILE **out, char *command, ...) {
2914 char *argv[11] = {command};
2916 int infd[2], outfd[2];
2920 va_start(ap, command);
2921 while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
2924 argv[argc] = NULL; /* make sure */
2927 if (pipe(infd) != 0) return 0;
2928 if (pipe(outfd) != 0) {
2929 close(infd[0]); close(infd[1]);
2934 switch(pid = fork()) {
2935 case -1: /* failure */
2936 close(infd[0]); close(infd[1]);
2937 close(outfd[0]); close(outfd[1]);
2942 close(infd[0]); close(infd[1]);
2943 close(outfd[0]); close(outfd[1]);
2944 execvp(command, argv);
2946 default: /* parent */
2947 *in = fdopen(infd[1], "w");
2948 *out = fdopen(outfd[0], "r");
2949 close(infd[0]); close(outfd[1]);
2956 \section{The Driver}
2958 The final C module we'll have is the one with the [[main()]]
2959 function. It's put together in a fairly straightforward way.
2963 <<main global variables>>
2964 <<main function declarations>>
2969 Equally, there's nothing particularly special about our headers.
2982 Now, after all the above modules, our main program doesn't have too
2983 much to do: it just has to interpret arguments and coordinate the
2984 intervening modules. Since we're being ``smart'', as well as parsing
2985 arguments, we'll decide whether the interface is going up or down
2986 depending on whether we were called as [[ifup]] or [[ifdown]].
2989 int main(int argc, char **argv) {
2990 <<variables local to main>>
2992 <<ensure environment is sane>>
2994 <<parse command name or die>>
2997 <<read interfaces files or die>>
2999 <<run commands for appropriate interfaces>>
3005 \subsection{Check the Environment}
3007 In the earlier code we assume that we have stdin, stdout and stderr all
3008 available. We need to assure that, just in case:
3015 <<ensure environment is sane>>=
3018 for (i = 0; i <= 2; i++) {
3019 if (fcntl(i, F_GETFD) == -1) {
3020 if (errno == EBADF && open("/dev/null", 0) == -1) {
3022 "%s: fd %d not available; aborting\n",
3025 } else if (errno == EBADF) {
3026 errno = 0; /* no more problems */
3028 /* some other problem -- eeek */
3037 \subsection{Configuring or Deconfiguring?}
3039 So the very first real thing we need to do is parse the command name. To
3040 do this, we'll obviously need to work out somewhere to store the result. A
3041 reasonable thing to do here is just to keep a function pointer about,
3042 which will point to one of the previously defined [[iface_up]] or
3043 [[iface_down]] functions, depending on which should be used on the
3044 specified interfaces.
3046 <<variables local to main>>=
3047 int (*cmds)(interface_defn *) = NULL;
3050 So given this, we can just:
3052 <<parse command name or die>>=
3056 <<set [[command]] to the base of the command name>>
3057 <<set [[cmds]] based on [[command]] or die>>
3061 And fill out each component in the reasonably obvious manner of:
3063 <<set [[command]] to the base of the command name>>=
3064 if ((command = strrchr(argv[0],'/'))) {
3065 command++; /* first char after / */
3067 command = argv[0]; /* no /'s in argv[0] */
3071 <<set [[cmds]] based on [[command]] or die>>=
3072 if (strcmp(command, "ifup")==0) {
3074 } else if (strcmp(command, "ifdown")==0) {
3077 fprintf(stderr,"This command should be called as ifup or ifdown\n");
3082 In addition, since our later behaviour varies depending on whether we're
3083 bringing interfaces up or taking them down we'll define two chunks to assist
3086 <<we're bringing interfaces up>>=
3090 <<we're taking interfaces down>>=
3091 (cmds == iface_down)
3094 The [[--allow]] option lets us limit the interfaces ifupdown will act on.
3095 It's implemented by having an [[allow_class]] that tells us which class
3096 of interfaces we're working with, and skipping interfaces that aren't
3097 in that class, like so:
3099 <<we're limiting to [[--allow]]ed interfaces>>=
3100 (allow_class != NULL)
3102 <<find [[iface]] in [[allow_class]] or [[continue]]>>=
3105 allowup_defn *allowup = find_allowup(defn, allow_class);
3106 if (allowup == NULL)
3109 for (i = 0; i < allowup->n_interfaces; i++) {
3110 if (strcmp(allowup->interfaces[i], iface) == 0)
3113 if (i >= allowup->n_interfaces)
3118 Finally, the behaviour might vary depending on whether we are
3119 excluding this interface or not. Notice that
3120 the exclude option can use a full interface name or substrings that
3121 match interfaces. A user could easily have unexpected behaviour
3122 if he uses a small string to do the match:
3124 <<we're [[--exclude]]ing this interface>>=
3125 (excludeint != NULL && strstr(iface,excludeint) != NULL)
3128 \subsection{Argument Handling}
3130 Okay, so next on our agenda is argument handling.
3132 We'll do argument handling via the GNU [[getopt]] function, which
3133 means we have to include the appropriate header, and define a cute
3134 little structure to represent out long options:
3140 <<variables local to main>>=
3141 struct option long_opts[] = {
3142 {"help", no_argument, NULL, 'h'},
3143 {"version", no_argument, NULL, 'V'},
3144 {"verbose", no_argument, NULL, 'v'},
3145 {"all", no_argument, NULL, 'a'},
3146 {"allow", required_argument, NULL, 3 },
3147 {"interfaces", required_argument, NULL, 'i'},
3148 {"exclude", required_argument, NULL, 'e'},
3149 {"no-act", no_argument, NULL, 'n'},
3150 {"no-mappings", no_argument, NULL, 1 },
3151 {"force", no_argument, NULL, 2 },
3156 The usual way of dealing with options then is to have a variable to store
3157 the various things. The only special note here is that we need to export
3158 [[no_act]] and [[verbose]] to the [[execute]] module.
3160 <<exported symbols>>=
3165 <<main global variables>>=
3170 <<variables local to main>>=
3172 int run_mappings = 1;
3174 char *allow_class = NULL;
3175 char *interfaces = "/etc/network/interfaces";
3176 char *statefile = "/etc/network/run/ifstate";
3177 char *excludeint = NULL ;
3180 We'll also have two helper functions to display usage information,
3183 <<main function declarations>>=
3184 static void usage(char *execname);
3185 static void help(char *execname);
3186 static void version(char *execname);
3190 static void usage(char *execname) {
3191 fprintf(stderr, "%s: Use --help for help\n", execname);
3197 static void version(char *execname) {
3198 printf("%s version " IFUPDOWN_VERSION "\n", execname);
3199 printf("Copyright (c) 1999-2005 Anthony Towns\n\n");
3202 "This program is free software; you can redistribute it and/or modify\n"
3203 "it under the terms of the GNU General Public License as published by\n"
3204 "the Free Software Foundation; either version 2 of the License, or (at\n"
3205 "your option) any later version.\n"
3213 static void help(char *execname) {
3214 printf("Usage: %s <options> <ifaces...>\n\n", execname);
3215 printf("Options:\n");
3216 printf("\t-h, --help\t\tthis help\n");
3217 printf("\t-V, --version\t\tcopyright and version information\n");
3218 printf("\t-a, --all\t\tde/configure all interfaces marked \"auto\"\n");
3219 printf("\t--allow CLASS\t\tignore non-\"allow-CLASS\" interfaces\n");
3220 printf("\t-i, --interfaces FILE\tuse FILE for interface definitions\n");
3221 printf("\t-n, --no-act\t\tprint out what would happen, but don't do it\n");
3222 printf("\t\t\t\t(note that this option doesn't disable mappings)\n");
3223 printf("\t-v, --verbose\t\tprint out what would happen before doing it\n");
3224 printf("\t--no-mappings\t\tdon't run any mappings\n");
3225 printf("\t--force\t\t\tforce de/configuration\n");
3230 Now, the meat of argument parsing is done with [[getopt()]] and a
3231 [[switch]], like so:
3233 <<parse arguments>>=
3236 c = getopt_long(argc, argv, "e:s:i:hVvna", long_opts, NULL);
3237 if (c == EOF) break;
3240 <<[[getopt]] possibilities>>
3244 <<check unreasonable arguments>>
3247 Now, our [[getopt]] possibilities are basically each option, or something
3248 really bad. Actual interface names are automagically collected at the end
3249 by [[getopt()]].So first, the legitimate cases get handled:
3251 <<[[getopt]] possibilities>>=
3253 interfaces = strdup(optarg);
3256 <<[[getopt]] possibilities>>=
3261 <<[[getopt]] possibilities>>=
3266 <<[[getopt]] possibilities>>=
3268 allow_class = strdup(optarg);
3271 <<[[getopt]] possibilities>>=
3276 <<[[getopt]] possibilities>>=
3281 <<[[getopt]] possibilities>>=
3286 <<[[getopt]] possibilities>>=
3288 excludeint = strdup(optarg);
3292 And we also have a help option and a version option:
3294 <<[[getopt]] possibilities>>=
3299 <<[[getopt]] possibilities>>=
3305 And we also have the possibility that the user is just making up
3308 <<[[getopt]] possibilities>>=
3314 After all that there are still some things that can be a bit weird. We
3315 can be told either to act on all interfaces (except the noauto ones),
3316 or we can be told to act on specific interface. We won't accept been
3317 told to do both, and we won't accept not being told to do one or the
3318 other. We can test these two cases as follows:
3320 <<check unreasonable arguments>>=
3321 if (argc - optind > 0 && do_all) {
3326 <<check unreasonable arguments>>=
3327 if (argc - optind == 0 && !do_all) {
3332 \subsection{Reading the Interfaces File}
3334 Since this has all been covered in a previous section, this is pretty
3337 <<variables local to main>>=
3338 interfaces_file *defn;
3341 <<read interfaces files or die>>=
3342 defn = read_interfaces(interfaces);
3344 fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n",
3345 argv[0], interfaces);
3350 \subsection{Execution}
3352 A broad overview of what we'll actually be doing is as follows:
3354 <<run commands for appropriate interfaces>>=
3355 <<lock 'n load ifupdown state>>
3356 <<determine target interfaces>>
3359 for (<<each target interface, [[i]]>>) {
3360 char iface[80], liface[80];
3362 <<initialize [[iface]] to [[i]]th target interface>>
3364 <<check ifupdown state (possibly [[continue]])>>
3367 if (<<we're limiting to [[--allow]]ed interfaces>>) {
3368 <<find [[iface]] in [[allow_class]] or [[continue]]>>
3371 if (<<we're [[--exclude]]ing this interface>>)
3374 if (<<we're bringing interfaces up>> && run_mappings) {
3378 <<bring interface up/down and update ifupdown state>>
3379 <<commit ifupdown state>>
3382 <<close ifupdown state>>
3385 We'll leave determining the appropriate target interfaces and dealing
3386 with the state until a little later. That leaves us with covering running
3387 the mappings and bringing the interface up or taking it down.
3389 Mappings are dealt with like so:
3393 mapping_defn *currmap;
3394 for (currmap = defn->mappings; currmap; currmap = currmap->next) {
3396 for (i = 0; i < currmap->n_matches; i++) {
3397 <<[[continue]] unless mapping matches>>
3405 We check if mappings match by using shell globs, so we'll need a new header
3406 to take care of that.
3409 #include <fnmatch.h>
3412 <<[[continue]] unless mapping matches>>=
3413 if (fnmatch(currmap->match[i], liface, 0) != 0)
3417 Actually running a mapping is fairly straightforward, thanks to our
3422 fprintf(stderr, "Running mapping script %s on %s\n",
3423 currmap->script, liface);
3425 run_mapping(iface, liface, sizeof(liface), currmap);
3428 Bringing an interface up or taking it down can be done thusly:
3430 <<bring interface up/down and update ifupdown state>>=
3432 interface_defn *currif;
3435 for (currif = defn->ifaces; currif; currif = currif->next) {
3436 if (strcmp(liface, currif->logical_iface) == 0) {
3439 <<run commands for [[currif]]; set [[failed]] on error>>
3442 /* Otherwise keep going: this interface may have
3443 * match with other address families */
3447 if (!okay && !force) {
3448 fprintf(stderr, "Ignoring unknown interface %s=%s.\n",
3451 <<update ifupdown state>>
3456 <<run commands for [[currif]]; set [[failed]] on error>>=
3458 currif->real_iface = iface;
3461 fprintf(stderr, "Configuring interface %s=%s (%s)\n",
3462 iface, liface, currif->address_family->name);
3465 switch(cmds(currif)) {
3467 printf("Don't seem to be have all the variables for %s/%s.\n",
3468 liface, currif->address_family->name);
3474 /* not entirely successful */
3480 printf("Internal error while configuring interface %s/%s (assuming it failed)\n",
3481 liface, currif->address_family->name);
3483 /* what happened here? */
3485 currif->real_iface = NULL;
3489 \subsection{Target Interfaces}
3491 So, if we're going to actually do something, we should probably figure
3492 out exactly what we're going to do it to. So, we need to know the set
3493 of interfaces we're going to hax0r. This is just an array of interfaces,
3494 either [[physical_iface]] or [[physical_iface=logical_iface]].
3496 <<variables local to main>>=
3497 int n_target_ifaces;
3498 char **target_iface;
3501 <<each target interface, [[i]]>>=
3502 i = 0; i < n_target_ifaces; i++
3505 We initialise this based on our command line arguments.
3507 <<determine target interfaces>>=
3509 if (<<we're bringing interfaces up>>) {
3510 allowup_defn *autos = find_allowup(defn, "auto");
3511 target_iface = autos ? autos->interfaces : NULL;
3512 n_target_ifaces = autos ? autos->n_interfaces : 0;
3513 } else if (<<we're taking interfaces down>>) {
3514 target_iface = state;
3515 n_target_ifaces = n_state;
3520 target_iface = argv + optind;
3521 n_target_ifaces = argc - optind;
3525 <<initialize [[iface]] to [[i]]th target interface>>=
3526 strncpy(iface, target_iface[i], sizeof(iface));
3527 iface[sizeof(iface)-1] = '\0';
3531 if ((pch = strchr(iface, '='))) {
3533 strncpy(liface, pch+1, sizeof(liface));
3534 liface[sizeof(liface)-1] = '\0';
3536 strncpy(liface, iface, sizeof(liface));
3537 liface[sizeof(liface)-1] = '\0';
3544 Since it's generally not feasible to rerun a mapping script after an
3545 interface is configured (since a mapping script may well bring the
3546 interface down while it's investigating matters), we need to maintain a
3547 statefile between invocations to keep track of which physical interfaces
3548 were mapped to which logical ones. We ought to use
3549 [[/var/run/ifupdown.state]] or something similar for this, but [[/var]]
3550 isn't guaranteed to be available until the network's up, so we'll use
3551 [[/etc/network/run/ifstate]] instead.
3553 <<variables local to main>>=
3554 char **state = NULL; /* list of iface=liface */
3559 We'll also use two helper functions: one to lookup an interface, and one to
3562 <<main function declarations>>=
3563 static int lookfor_iface(char **ifaces, int n_ifaces, char *iface);
3567 static int lookfor_iface(char **ifaces, int n_ifaces, char *iface) {
3569 for (i = 0; i < n_ifaces; i++) {
3570 if (strncmp(iface, ifaces[i], strlen(iface)) == 0) {
3571 if (ifaces[i][strlen(iface)] == '=') {
3580 <<main function declarations>>=
3581 static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces,
3586 static void add_to_state(char ***ifaces, int *n_ifaces, int *max_ifaces,
3589 assert(*max_ifaces >= *n_ifaces);
3590 if (*max_ifaces == *n_ifaces) {
3591 *max_ifaces = (*max_ifaces * 2) + 1;
3592 *ifaces = realloc(*ifaces, sizeof(**ifaces) * *max_ifaces);
3593 if (*ifaces == NULL) {
3599 (*ifaces)[(*n_ifaces)++] = new_iface;
3603 The state file is opened and locked, blocking parallel updates:
3605 <<main function declarations>>=
3606 static int lock_fd (int fd);
3610 static int lock_fd (int fd) {
3613 lock.l_type = F_WRLCK;
3614 lock.l_whence = SEEK_SET;
3618 if (fcntl(fd, F_SETLKW, &lock) < 0) {
3627 <<variables local to main>>=
3628 static FILE *state_fp = NULL;
3631 <<lock 'n load ifupdown state>>=
3633 state_fp = fopen(statefile, no_act ? "r" : "a+");
3634 if (state_fp == NULL && !no_act) {
3636 "%s: failed to open statefile %s: %s\n",
3637 argv[0], statefile, strerror(errno));
3641 if (state_fp != NULL) {
3648 if ((flags = fcntl(fileno(state_fp), F_GETFD)) < 0
3649 || fcntl(fileno(state_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
3651 "%s: failed to set FD_CLOEXEC on statefile %s: %s\n",
3652 argv[0], statefile, strerror(errno));
3656 if (lock_fd (fileno(state_fp)) < 0) {
3658 "%s: failed to lock statefile %s: %s\n",
3659 argv[0], statefile, strerror(errno));
3666 while((p = fgets(buf, sizeof buf, state_fp)) != NULL) {
3669 pch = buf + strlen(buf) - 1;
3670 while(pch > buf && isspace(*pch)) pch--;
3674 while(isspace(*pch)) pch++;
3676 add_to_state(&state, &n_state, &max_state, strdup(pch));
3682 <<close ifupdown state>>=
3683 if (state_fp != NULL) {
3690 <<commit ifupdown state>>=
3691 if (state_fp != NULL && !no_act) {
3694 if (ftruncate(fileno(state_fp), 0) < 0)
3697 "%s: failed to truncate statefile %s: %s\n",
3698 argv[0], statefile, strerror(errno));
3703 for (i = 0; i < n_state; i++) {
3704 fprintf(state_fp, "%s\n", state[i]);
3710 This leaves our two useful chunks. The first checks to ensure what we're
3711 proposing to do is reasonable (ie, we're not downing an interface that's
3712 not up, or uping one that's not down).
3714 <<check ifupdown state (possibly [[continue]])>>=
3716 int already_up = lookfor_iface(state, n_state, iface);;
3718 if (<<we're bringing interfaces up>>) {
3719 if (already_up != -1) {
3721 "%s: interface %s already configured\n",
3725 } else if (<<we're taking interfaces down>>) {
3726 if (already_up == -1) {
3727 fprintf(stderr, "%s: interface %s not configured\n",
3731 strncpy(liface, strchr(state[already_up], '=') + 1, 80);
3739 And finally, we also need to be able to update the state as we bring
3740 interfaces up and down.
3742 <<update ifupdown state>>=
3744 int already_up = lookfor_iface(state, n_state, iface);
3746 if (<<we're bringing interfaces up>>) {
3748 malloc(strlen(iface) + 1 + strlen(liface) + 1);
3749 sprintf(newiface, "%s=%s", iface, liface);
3751 if (already_up == -1) {
3753 printf("Failed to bring up %s.\n", liface);
3755 add_to_state(&state, &n_state, &max_state, newiface);
3758 free(state[already_up]);
3759 state[already_up] = newiface;
3761 } else if (<<we're taking interfaces down>>) {
3762 if (already_up != -1) {
3763 state[already_up] = state[--n_state];
3773 \section{Linux Address Families}
3776 unsigned int mylinuxver();
3777 unsigned int mylinux(int,int,int);
3778 int execable(char *);
3786 #include <sys/utsname.h>
3787 #include <sys/stat.h>
3789 #include "archlinux.h"
3791 unsigned int mylinuxver() {
3792 static int maj = -1, rev, min;
3798 maj = atoi(u.release);
3799 pch = strchr(u.release, '.');
3801 pch = strchr(pch+1, '.');
3805 return mylinux(maj,rev,min);
3808 unsigned int mylinux(int maj, int rev, int min) {
3809 return min | rev << 10 | maj << 13;
3812 int execable(char *program) {
3815 if (0 == stat(program, &buf)) {
3816 if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) return 1;
3822 \subsection{IPv4 Address Family}
3824 <<address family declarations>>=
3825 extern address_family addr_inet;
3828 <<address family references>>=
3842 This method may be used to define the IPv4 loopback interface.
3845 ifconfig %iface% 127.0.0.1 up
3846 route add -net 127.0.0.0 if ( mylinuxver() < mylinux(2,1,100) )
3849 ifconfig %iface% down
3855 This method may be used to define ethernet interfaces with statically
3856 allocated IPv4 addresses.
3859 address address -- Address (dotted quad) *required*
3860 netmask netmask -- Netmask (dotted quad) *required*
3861 broadcast broadcast_address -- Broadcast address (dotted quad)
3862 network network_address -- Network address (dotted quad) *required \
3864 metric metric -- Routing metric for default gateway (integer)
3865 gateway address -- Default gateway (dotted quad)
3866 pointopoint address -- Address of other end point (dotted quad). \
3867 Note the spelling of "point-to".
3868 media type -- Medium type, driver dependent
3869 hwaddress class address -- Hardware Address. /class/ is one of \
3870 *ether*, *ax25*, *ARCnet* or *netrom*. \
3871 /address/ is dependent on the above \
3873 mtu size -- MTU size
3876 [[ ifconfig %iface% hw %hwaddress%]]
3877 ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] \
3878 [[pointopoint %pointopoint%]] [[media %media%]] [[mtu %mtu%]] \
3880 route add -net %network% \
3881 if ( mylinuxver() < mylinux(2,1,100) )
3882 [[ route add default gw %gateway% [[metric %metric%]] %iface% ]]
3885 [[ route del default gw %gateway% [[metric %metric%]] %iface% ]]
3886 ifconfig %iface% down
3892 This method may be used to define interfaces for which no configuration
3893 is done by default. Such interfaces can be configured manually by
3894 means of *up* and *down* commands or /etc/network/if-*.d scripts.
3904 This method may be used to obtain an address via DHCP with any of
3905 the tools: dhclient, pump, udhcpc, dhcpcd.
3906 (They have been listed in their order of precedence.)
3907 If you have a complicated DHCP setup you should
3908 note that some of these clients use their own configuration files
3909 and do not obtain their configuration information via *ifup*.
3912 hostname hostname -- Hostname to be requested (pump, dhcpcd, udhcpc)
3913 leasehours leastime -- Preferred lease time in hours (pump)
3914 leasetime leasetime -- Preferred lease time in seconds (dhcpcd)
3915 vendor vendor -- Vendor class identifier (dhcpcd)
3916 client client_id -- Client identifier (dhcpcd, udhcpc)
3917 hwaddress class address -- Hardware Address. /class/ is one of \
3918 *ether*, *ax25*, *ARCnet* or *netrom*. \
3919 /address/ is dependent on this choice.
3922 [[ifconfig %iface% hw %hwaddress%]]
3923 dhclient3 -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
3924 if (execable("/sbin/dhclient3"))
3925 dhclient -e -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
3926 elsif (execable("/sbin/dhclient"))
3927 pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]] \
3928 elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
3929 udhcpc -n -p /var/run/udhcpc.%iface%.pid -i %iface% [[-H %hostname%]] \
3931 elsif (execable("/sbin/udhcpc") && mylinuxver() >= mylinux(2,2,0))
3932 dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] \
3933 [[-l %leasetime%]] %iface% \
3934 elsif (execable("/sbin/dhcpcd"))
3937 dhclient3 -r -pf /var/run/dhclient.%iface%.pid -lf /var/run/dhclient.%iface%.leases %iface% \
3938 if (execable("/sbin/dhclient3"))
3939 cat /var/run/dhclient.%iface%.pid | xargs -i kill -TERM {} \
3940 elsif (execable("/sbin/dhclient"))
3941 pump -i %iface% -r \
3942 elsif (execable("/sbin/pump") && mylinuxver() >= mylinux(2,1,100))
3943 cat /var/run/udhcpc.%iface%.pid | xargs -i kill -TERM {} \
3944 elsif (execable("/sbin/udhcpc"))
3946 elsif (execable("/sbin/dhcpcd"))
3948 ifconfig %iface% down
3954 This method may be used to obtain an address via bootp.
3957 bootfile file -- Tell the server to use /file/ as the bootfile.
3958 server address -- Use the IP address /address/ to communicate with \
3960 hwaddr addr -- Use /addr/ as the hardware address instead of \
3961 whatever it really is.
3964 bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] \
3965 [[--hwaddr %hwaddr%]] --returniffail --serverbcast
3968 ifconfig down %iface%
3974 This method uses pon/poff to configure a PPP interface. See those
3975 commands for details.
3977 provider name -- Use /name/ as the provider (from /etc/ppp/peers).
3987 This method uses wvdial to configure a PPP interface. See that command
3990 provider name -- Use /name/ as the provider (from /etc/ppp/peers).
3992 /sbin/start-stop-daemon --start -x /usr/bin/wvdial \
3993 -p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]
3995 /sbin/start-stop-daemon --stop -x /usr/bin/wvdial \
3996 -p /var/run/wvdial.%iface% -s 2
4002 \subsection{IPv6 Address Family}
4004 <<address family declarations>>=
4005 extern address_family addr_inet6;
4008 <<address family references>>=
4013 address_family inet6
4018 This method may be used to define the IPv6 loopback interface.
4020 ifconfig %iface% add ::1
4022 ifconfig %iface% del ::1
4026 This method may be used to define interfaces with statically assigned
4030 address address -- Address (colon delimited) *required*
4031 netmask mask -- Netmask (number of bits, eg 64) *required*
4032 gateway address -- Default gateway (colon delimited)
4033 media type -- Medium type, driver dependent
4034 hwaddress class address -- Hardware Address. /class/ is one of \
4035 *ether*, *ax25*, *ARCnet* or *netrom*. \
4036 /address/ is dependent on this choice.
4037 mtu size -- MTU size
4039 ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up
4040 ifconfig %iface% add %address%/%netmask%
4041 [[ route -A inet6 add ::/0 gw %gateway% ]]
4044 ifconfig %iface% down
4048 This method may be used to setup an IPv6-over-IPv4 tunnel. It requires
4049 the *ip* command from the *iproute* package.
4052 address address -- Address (colon delimited)
4053 netmask mask -- Netmask (number of bits, eg 64)
4054 endpoint address -- Address of other tunnel endpoint (IPv4 \
4055 dotted quad) *required*
4056 local address -- Address of the local endpoint (IPv4 \
4058 gateway address -- Default gateway (colon delimited)
4059 ttl time -- TTL setting
4062 ip tunnel add %iface% mode sit remote %endpoint% [[local %local%]] \
4064 ip link set %iface% up
4065 [[ ip addr add %address%/%netmask% dev %iface% ]]
4066 [[ ip route add %gateway% dev %iface% ]]
4067 [[ ip route add ::/0 via %gateway% dev %iface% ]]
4070 ip tunnel del %iface%
4073 \subsection{IPX Address Family}
4075 <<address family declarations>>=
4076 extern address_family addr_ipx;
4079 <<address family references>>=
4089 This method may be used to setup an IPX interface. It requires the
4090 /ipx_interface/ command.
4093 frame type -- /type/ of ethernet frames to use (e.g. *802.2*)
4094 netnum id -- Network number
4097 ipx_interface add %iface% %frame% %netnum%
4100 ipx_interface del %iface% %frame%
4104 This method may be used to setup an IPX interface dynamically.
4107 frame type -- /type/ of ethernet frames to use (e.g. *802.2*)
4110 ipx_interface add %iface% %frame%
4113 ipx_interface del %iface% %frame%
4117 \bibliography{biblio}
4118 \bibliographystyle{unsrt}