AutoIPの実装サンプル
Posted: 2015年5月29日(金) 18:33
対象:
μNet3/Compact、μNet3/Standard
概要:
本項では、μNet3でAutoIP機能を使用したい場合の実装例を記載します。
AutoIPは下記のAPIを使用する事で実現する事ができます。
・IPアドレスの設定およびIPアドレス競合を検知した場合のコールバック関数設定を行う
ER net_cfg(UH num, UH opt, VP val)
・IPアドレスの競合探知を行う
ER net_acd(UH dev_num, T_NET_ACD *acd)
実装詳細:
・AutoIPを設定するタイミングについて
静的IPやDHCPサーバなどを介した動的IPの設定が出来なかった場合に
AutoIPの設定が実行されます。
・AutoIPの設定アドレスの範囲について
設定されるアドレスの範囲は「169.254.1.0?169.254.254.255」となります。
※169.254.0.0?169.254.0.255と169.254.255.0?169.254.255.255は予約済で使用できません。
・アドレス取得時の注意点について
まずアドレス取得は下記のような工程を辿ります。
1.ランダムに選択されたリンクローカルアドレスを生成。
2.アドレス競合チェックのためにARP通知などを行う。
3.競合していた場合は「1.」の工程に戻る。
上記の過程でアドレス取得を行っているホスト側は、アドレス競合の回数を記憶する必要があり、
もしその回数がMAX_CONFLICTS(※1)で定義されている値以上になった場合、ホスト側はアドレス取得工程の
速度をRATE_LIMIT_INTERVAL(※2)で定義されている値に制限しなければなりません。
※1:MAX_CONFLICTSの値はデフォルトで「10(回)」と既定されています。
※2:RATE_LIMIT_INTERVALの値はデフォルトで「60(秒)」と既定されています。
サンプルコード:
上記を踏まえて下記にμNet3でのAutoIP機能の実装コードを記載します。
実装サンプルAPIの説明:
【書式】
ER set_apipa( UH dev_num )
【パラメータ】
UH dev_num : デバイス番号
【戻り値】
ER ercd 正常終了(E_OK)またはエラーコード
【解説】
dev_numで指定されるデバイスに対して、AutoIPの設定を行います。
このサンプルAPIはリンクローカルアドレスが取得できるまで制御を戻しません。
※RFC3927の仕様ではAutoIPの取得要求の回数上限は得に設けられていません。
これはAutoIPが最大6万台以上のアドレス空間を保持している事と、そのアドレスが
ローカルネットワーク内でしか使われないからであると考えられます。
競合の検出と対処方法:
以降の内容は競合検出のコールバックの処理実装に絡む内容である為、
必ずしも下記に準じる必要はありません。(コールバックの実装はユーザに委ねられます)
従って、あくまで参考資料として参照ください。
AutoIP取得後にアドレスの競合が検出された場合の対処法として
RFC3927では下記が既定されています。
a) 競合を検出した場合、ホストはアドレスの使用を即刻中止しホスト側へエラーを通知しても良い。(MAY)
b) 何らかの理由でアドレスを保持したい場合、ホストは競合通知の時刻を記録した上で、
アドレスの継続保持を宣言(ARP Announce)を一度通知しても良い。(MAY)
但し、競合検出がDEFEND_INTERVAL(※1)秒以内に再び現れた場合、ホストは「(a)」の処理を実施する。(MUST)
ホストは競合通知を無視してはいけない。従って上記(a)または(b)の処理を実行しなければならない。(MUST)
※1:DEFEND_INTERVALの値はデフォルトで「10(秒)」と既定されています。
これらに対処するため、一番シンプルな方法は下記の様に(a)の処理のみを実装します。
可能な限りIPアドレスの保持を試みたい場合は下記の様に(a)(b)の処理を実装します。
参考文献:
http://tools.ietf.org/html/rfc3927
μNet3/Compact、μNet3/Standard
概要:
本項では、μNet3でAutoIP機能を使用したい場合の実装例を記載します。
AutoIPは下記のAPIを使用する事で実現する事ができます。
・IPアドレスの設定およびIPアドレス競合を検知した場合のコールバック関数設定を行う
ER net_cfg(UH num, UH opt, VP val)
・IPアドレスの競合探知を行う
ER net_acd(UH dev_num, T_NET_ACD *acd)
実装詳細:
・AutoIPを設定するタイミングについて
静的IPやDHCPサーバなどを介した動的IPの設定が出来なかった場合に
AutoIPの設定が実行されます。
・AutoIPの設定アドレスの範囲について
設定されるアドレスの範囲は「169.254.1.0?169.254.254.255」となります。
※169.254.0.0?169.254.0.255と169.254.255.0?169.254.255.255は予約済で使用できません。
・アドレス取得時の注意点について
まずアドレス取得は下記のような工程を辿ります。
1.ランダムに選択されたリンクローカルアドレスを生成。
2.アドレス競合チェックのためにARP通知などを行う。
3.競合していた場合は「1.」の工程に戻る。
上記の過程でアドレス取得を行っているホスト側は、アドレス競合の回数を記憶する必要があり、
もしその回数がMAX_CONFLICTS(※1)で定義されている値以上になった場合、ホスト側はアドレス取得工程の
速度をRATE_LIMIT_INTERVAL(※2)で定義されている値に制限しなければなりません。
※1:MAX_CONFLICTSの値はデフォルトで「10(回)」と既定されています。
※2:RATE_LIMIT_INTERVALの値はデフォルトで「60(秒)」と既定されています。
サンプルコード:
上記を踏まえて下記にμNet3でのAutoIP機能の実装コードを記載します。
コード: 全て選択
/*---------------------------------------------------------------------------*/
/* プロトタイプ定義 */
/*---------------------------------------------------------------------------*/
extern ER set_apipa( UH dev_num );
static ER apipa_acd_cbk( T_NET_ACD * acd );
/*---------------------------------------------------------------------------*/
/* 定数定義 */
/*---------------------------------------------------------------------------*/
#define AIP_CFL_CNT 10 /* アドレス競合の速度制限適用までの回数 */
#define AIP_RATE_INT 60*1000 /* アドレス取得の速度制限のインターバル */
static ER apipa_acd_cbk(T_NET_ACD * acd)
{
// アドレス取得後に競合が発生した場合にコールバックされる(処理内容は任意)
// E_OK 以外を返した場合、ARP Announceを通知しない(つまりIPアドレスを破棄する)
// E_OK を返した場合、ARP Announceを通知する(つまりIPアドレスを保持する)
}
ER set_apipa( UH dev_num )
{
/* AutoIPのベース情報 */
T_NET_ADR adr = { 0x00, 0x00, 0xA9FE0000, 0x00000000, 0xFFFF0000 };
T_NET_ACD acd; /* アドレス競合情報 */
SYSTIM sysTim; /* システム時間 */
UW conflict_cnt; /* アドレス競合回数 */
ER ercd; /* 戻り値 */
/*-----------------------------------------------------------------------*/
/* 乱数初期化 */
/*-----------------------------------------------------------------------*/
get_tim( &sysTim );
net_rand_seed( sysTim.ltime );
/*-----------------------------------------------------------------------*/
/* AutoIP取得処理 */
/*-----------------------------------------------------------------------*/
for ( conflict_cnt = 1; ; conflict_cnt++ ) {
/* ランダムなリンクローカルアドレス生成(169.254.XXX.XXX) */
adr.ipaddr &= 0xFFFF0000;
adr.ipaddr |= (net_rand() % 253 + 1) << 8 | (net_rand() % 253 + 1);
/* ホストにリンクローカルアドレスを設定 */
ercd = net_cfg( dev_num, NET_IP4_CFG, (VP)&adr );
if ( ercd != E_OK ) {
return ercd;
}
/* リンクローカルアドレスの競合探知を行う */
ercd = net_acd( dev_num, &acd );
if ( ercd == E_OK ) {
/* 競合無しなので、後々競合検知した場合のコールバック関数設定 */
ercd = net_cfg( dev_num, NET_ACD_CBK, (VP)apipa_acd_cbk );
break;
} else if ( ercd != E_SYS ) {
/* E_OKでもE_SYSでもない場合、net_acd関数で異常発生 */
break;
}
/* アドレス競合の回数が既定以上の場合、速度制限を行う */
if ( conflict_cnt >= AIP_CFL_CNT ) {
/* ARPストーム防止 */
tslp_tsk( AIP_RATE_INT );
}
}
return ercd;
}
【書式】
ER set_apipa( UH dev_num )
【パラメータ】
UH dev_num : デバイス番号
【戻り値】
ER ercd 正常終了(E_OK)またはエラーコード
【解説】
dev_numで指定されるデバイスに対して、AutoIPの設定を行います。
このサンプルAPIはリンクローカルアドレスが取得できるまで制御を戻しません。
※RFC3927の仕様ではAutoIPの取得要求の回数上限は得に設けられていません。
これはAutoIPが最大6万台以上のアドレス空間を保持している事と、そのアドレスが
ローカルネットワーク内でしか使われないからであると考えられます。
競合の検出と対処方法:
以降の内容は競合検出のコールバックの処理実装に絡む内容である為、
必ずしも下記に準じる必要はありません。(コールバックの実装はユーザに委ねられます)
従って、あくまで参考資料として参照ください。
AutoIP取得後にアドレスの競合が検出された場合の対処法として
RFC3927では下記が既定されています。
a) 競合を検出した場合、ホストはアドレスの使用を即刻中止しホスト側へエラーを通知しても良い。(MAY)
b) 何らかの理由でアドレスを保持したい場合、ホストは競合通知の時刻を記録した上で、
アドレスの継続保持を宣言(ARP Announce)を一度通知しても良い。(MAY)
但し、競合検出がDEFEND_INTERVAL(※1)秒以内に再び現れた場合、ホストは「(a)」の処理を実施する。(MUST)
ホストは競合通知を無視してはいけない。従って上記(a)または(b)の処理を実行しなければならない。(MUST)
※1:DEFEND_INTERVALの値はデフォルトで「10(秒)」と既定されています。
これらに対処するため、一番シンプルな方法は下記の様に(a)の処理のみを実装します。
コード: 全て選択
ER g_aip_detect_err = E_OK; /* AutoIPでの競合エラー */
static ER apipa_acd_cbk(T_NET_ACD * acd)
{
/* 競合を検出した場合、即座にアドレスを破棄する */
g_aip_detect_err = E_SYS;
return E_SYS;
}
ホスト側のタスク()
{
for ( ; ; ) {
・
・
// AutoIPエラーの検出
if ( g_aip_detect_err != E_OK ) {
// エラーを検出した時の処理
}
・
・
}
}
コード: 全て選択
ER g_aip_detect_err = E_OK; /* AutoIPでの競合エラー */
#define AIP_DFD_INT 10*1000 /* アドレス破棄判定用インターバル */
static ER apipa_acd_cbk(T_NET_ACD * acd)
{
static UD last_time = 0; /* 最後に競合検出した時間 */
UD now_time; /* 競合検出した時間 */
SYSTIM sysTim; /* システム時間 */
/* 現在のシステム時刻を取得 */
get_tim( &sysTim );
now_time = (UD)sysTim.utime << 32 | (UD)sysTim.ltime;
/* 最後に競合した時間を計算してアドレス破棄を判定する */
if ( last_time != 0 && (now_time - last_time) < AIP_DFD_INT ) {
/* E_SYSを返す場合、アドレス保持の継続宣言を行わない */
g_aip_detect_err = E_SYS;
return E_SYS;
}
/* 最後に競合検出した時間を更新 */
last_time = now_time;
/* E_OKを返す場合、アドレス保持の継続宣言を行う */
return E_OK;
}
ホスト側のタスク()
{
for ( ; ; ) {
・
・
// AutoIPエラーの検出
if ( g_aip_detect_err != E_OK ) {
// エラーを検出した時の処理
}
・
・
}
}
http://tools.ietf.org/html/rfc3927