1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<meta name="generator" content="HTML Tidy, see www.w3.org" />
<title>Configuring Multiple IP Addresses</title>
</head>
<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
vlink="#000080" alink="#FF0000">
<!--#include virtual="../header_l2.html" -->
<h1 align="CENTER">Configuring Multiple IP Addresses</h1>
<pre>
This material is originally from John Ioannidis (ji@polaris.ctr.columbia.edu)
I have condensed it some and applied some corrections for SunOS 4.1.x
courtesy of Chuck Smoko (csmoko@relay.nswc.navy.mil).
Bob Baggerman (bob@bizweb.com)
12 Jan 94
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
John Ionnidis writes:
This is a topic that comes up once in a while on comp.protocols.tcp-ip
and other newsgroups. The question is, how to get a machine with one
network interface to respond to more than one IP addresses.
I have a solution than might suit you. For my doctoral work (there's
a paper about it in this year's ('91) SIGCOMM, also available for
anonymous FTP from cs.columbia.edu:/pub/ji/sigcomm*.ps.Z), I've
developed what I call the "Virtual Interface" (VIF). To the networking
code, it looks like an interface. It gets ifattach()ed when you open
the /dev/vif* device, and then you can ifconfig it as you like. It
does not have an if_input procedure; it only has an if_output. Packets
that it receives (from higher-level protocols) which have its
IP address, it simply loops back (like any well-behaved if driver).
Packets that it receives that are destined for some other address, it
encapsulates in an encapsulation protocol I call IPIP (IP-within-IP,
protocol number IPPROTO_IPIP == 94), and sends it to another machine
that groks that encapsulation protocol. This feature you won't need,
but here's how to have multiple IP addresses on a machine with a
single real interface:
Let's say your primary interface's IP address is 198.3.2.1, and you
also want it to respond to addresses 198.4.3.2 and 198.5.4.3 (note
that these are three distinct class C addresses in three distinct
class C nets). Here are the ifconfigs:
ifconfig le0 198.3.2.1 up -trailers # config primary interface
ifconfig vif0 198.4.3.2 up # config first virtual interface
route delete net 198.4.3 198.4.3.2 # delete spurious route
route add host 198.4.3.2 198.4.3.2 0 # add route for this i/f
ifconfig vif1 198.5.4.3 up # config second virtual interface
route delete net 198.5.4 198.5.4.3 # delete spurious route
route add host 198.5.4.3 198.5.4.3 0 # add route for this i/f
The route deletes are needed because the ifconfig creates a default
route to the interface's network, which can cause problems; all that's
needed is the (host) route to the interface's address.
Now, get le0's ethernet address (say, 8:0:20:3:2:1), and add the
following static ARP entries:
arp -s 198.4.3.2 8:0:20:3:2:1 pub
arp -s 198.5.4.3 8:0:20:3:2:1 pub
This will cause any ARP requests for the VIF addresses to be replied
with your machine's ethernet address.
Now, make sure your default route is to your segment's gateway,
through the real interface. Finally, make sure your routers and/or
hosts on the same segment as yours know that 198.4.3.2 and 198.5.4.3
are on that cable.
Here's what you've accomplished.
ARP requests for any of your host's addresses will be replied to with
the host's ethernet address (the real one, because that's what it is,
the virtual ones because of the public static arp entries). Packets
reaching your host with any of these addresses will be accepted by the
ip_input routine because they match the address of one of the host's
interfaces. Packets leaving your host can have any of its addresses
(real and virtual).
The code for vif follows. To use it, put the stuff in netinet/if_vif.c
and netinet/if_vif.h, configure your kernel with the number of
virtual interfaces you want using a line like:
pseudo-device vif4 # Virtual IP interface
in your configuration file, and the line
netinet/if_vif.c optional vif device-driver
in the "files" file. Also, add the appropriate entries in conf.c, so
that you can access the if_attach() routine when you open the device:
-------------------------- conf.c------------------------------------------
add this in the appropriate place in the headers of conf.c:
--------------------
#include "vif.h"
#if NVIF > 0
int vifopen(), vifclose(), vifread(), vifwrite(), vifselect(), vifioctl();
#else
#define vifopen nodev
#define vifclose nodev
#define vifread nodev
#define vifwrite nodev
#define vifselect nodev
#define vifioctl nodev
#endif
--------------------
then, way down in the definition for cdevsw[]:
--------------------
vifopen, vifclose, vifread, vifwrite, /*14*/
vifioctl, nodev, nodev, 0,
0, nodev,
--------------------
Make sure you remember the correct major device number, 14 in this case!
---------------------------------------------------------------------------
Finally, here's the code. It has the tunneling pieces removed (you
need more code to use that anyway), and it comes from a Mach 2.6
kernel; it should compile on any Berkeley-derived unix with minor
changes (most likely only in the includes).
---------------------netinet/if_vif.h--------------------------------------
typedef struct
{
struct ifnet vif_if;
struct ifnet *vif_sif; /* slave interface */
int vif_flags;
} vif_softc_t;
#define VIFMTU (1024+512)
---------------------------------------------------------------------------
and
---------------------netinet/if_vif.c--------------------------------------
/*
* Virtual IP interface module.
*/
#include "param.h"
#include "../sys/systm.h"
#include "../sys/mbuf.h"
#include "../sys/socket.h"
#include "../sys/errno.h"
#include "../sys/ioctl.h"
#include "../net/if.h"
#include "../net/netisr.h"
#include "../net/route.h"
#ifdef INET
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/in_var.h"
#include "../netinet/ip.h"
#endif
#include "in_pcb.h"
#include "vif.h"
typedef struct
{
struct ifnet vif_if;
struct ifnet *vif_sif; /* slave interface */
int vif_flags;
} vif_softc_t;
#define VIFMTU (1024+512)
vif_softc_t vif_softc[NVIF];
int vifs_inited = 0;
vifattach()
{
register int i;
register struct ifnet *ifp;
int vifoutput(), vififioctl();
for (i=0; i<NVIF; i++)
{
ifp = &vif_softc[i].vif_if;
ifp->if_name = "vif";
ifp->if_unit = i;
ifp->if_mtu = VIFMTU;
ifp->if_flags = IFF_LOOPBACK | IFF_NOARP;
ifp->if_ioctl = vififioctl;
ifp->if_output = vifoutput;
if_attach(ifp);
}
}
vifopen(dev, flag)
int dev, flag;
{
int unit;
if (!vifs_inited)
{
vifattach();
vifs_inited = 1;
printf("vif initialized\n");
}
unit = minor(dev);
if ((unit < 0) || (unit >= NVIF))
{
return ENXIO;
}
return 0;
}
vifclose(dev, flag)
int dev, flag;
{
return 0;
}
vifread()
{
return ENXIO;
}
vifwrite()
{
return ENXIO;
}
vifselect()
{
return ENXIO;
}
vifoutput(ifp, m0, dst)
struct ifnet *ifp;
register struct mbuf *m0;
struct sockaddr *dst;
{
int s;
register struct ifqueue *ifq;
struct mbuf *m;
struct sockaddr_in *din;
if (dst->sa_family != AF_INET)
{
printf("%s%d: can't handle af%d\n",
ifp->if_name, ifp->if_unit,
dst->sa_family);
m_freem(m0);
return (EAFNOSUPPORT);
}
din = (struct sockaddr_in *)dst;
if (din->sin_addr.s_addr == IA_SIN(ifp->if_addrlist)->sin_addr.s_addr)
{
/* printf("%s%d: looping\n", ifp->if_name, ifp->if_unit); */
/*
* Place interface pointer before the data
* for the receiving protocol.
*/
if (m0->m_off <= MMAXOFF &&
m0->m_off >= MMINOFF + sizeof(struct ifnet *)) {
m0->m_off -= sizeof(struct ifnet *);
m0->m_len += sizeof(struct ifnet *);
} else {
MGET(m, M_DONTWAIT, MT_HEADER);
if (m == (struct mbuf *)0)
return (ENOBUFS);
m->m_off = MMINOFF;
m->m_len = sizeof(struct ifnet *);
m->m_next = m0;
m0 = m;
}
*(mtod(m0, struct ifnet **)) = ifp;
s = splimp();
ifp->if_opackets++;
ifq = &ipintrq;
if (IF_QFULL(ifq)) {
IF_DROP(ifq);
m_freem(m0);
splx(s);
return (ENOBUFS);
}
IF_ENQUEUE(ifq, m0);
schednetisr(NETISR_IP);
ifp->if_ipackets++;
splx(s);
return (0);
}
return EHOSTUNREACH;
}
/*
* Process an ioctl request.
*/
/* ARGSUSED */
vififioctl(ifp, cmd, data)
register struct ifnet *ifp;
int cmd;
caddr_t data;
{
int error = 0;
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
/*
* Everything else is done at a higher level.
*/
break;
default:
error = EINVAL;
}
return (error);
}
vifioctl(dev, cmd, arg, mode)
dev_t dev;
int cmd;
caddr_t arg;
int mode;
{
int unit;
unit = minor(dev);
if ((unit < 0) || (unit >= NVIF))
return ENXIO;
return EINVAL;
}
----------------------------------------------------------------------------
To use it, compile your kernel, and reboot. Then create the vif
device:
# mknod /dev/vif c 14 0
(or whatever major number it ended up being), and echo something into
it:
# echo > /dev/vif
This will cause the device to be opened, which will if_attach the
interfaces. If you feel like playing with the code, you may want to
kmem_alloc() the vif_softc structure at open time, and use the minor
number of the device to tell it how many interfaces to create.
Now you can go ahead and ifconfig <em>etc.</em>
I'll be happy to answer minor questions, and hear about success and
failure stories, but I cannot help you if you don't already know how
to hack kernels.
Good luck!
/ji
In-Real-Life: John "Heldenprogrammer" Ioannidis
E-Mail-To: ji@cs.columbia.edu
V-Mail-To: +1 212 854 8120
P-Mail-To: 450 Computer Science \n Columbia University \n New York, NY 10027
</pre>
<p>Note: there is also a <a
href="http://www.multihost.com/">commercial-product-turned-freeware
called "Col. Patch"</a> which does this as a loadable kernel
module for SunOS 4.1.3_U1.</p>
<p><!--#include virtual="footer.html" -->
</p>
</body>
</html>
|